refactor collections store
This commit is contained in:
parent
cd82083e09
commit
05c5bdf63c
|
@ -9,7 +9,6 @@ import Tree, {
|
||||||
TreeSourcePosition,
|
TreeSourcePosition,
|
||||||
TreeDestinationPosition,
|
TreeDestinationPosition,
|
||||||
} from "@atlaskit/tree";
|
} from "@atlaskit/tree";
|
||||||
import useCollectionStore from "@/store/collections";
|
|
||||||
import { Collection } from "@prisma/client";
|
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";
|
||||||
|
@ -17,6 +16,7 @@ import { useRouter } from "next/router";
|
||||||
import useAccountStore from "@/store/account";
|
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";
|
||||||
|
|
||||||
interface ExtendedTreeItem extends TreeItem {
|
interface ExtendedTreeItem extends TreeItem {
|
||||||
data: Collection;
|
data: Collection;
|
||||||
|
@ -24,7 +24,9 @@ interface ExtendedTreeItem extends TreeItem {
|
||||||
|
|
||||||
const CollectionListing = () => {
|
const CollectionListing = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { collections, updateCollection } = useCollectionStore();
|
const updateCollection = useUpdateCollection();
|
||||||
|
const { data: { response: collections } = { response: [] } } =
|
||||||
|
useCollections();
|
||||||
const { account, updateAccount } = useAccountStore();
|
const { account, updateAccount } = useAccountStore();
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -151,7 +153,7 @@ const CollectionListing = () => {
|
||||||
const updatedCollectionOrder = [...account.collectionOrder];
|
const updatedCollectionOrder = [...account.collectionOrder];
|
||||||
|
|
||||||
if (source.parentId !== destination.parentId) {
|
if (source.parentId !== destination.parentId) {
|
||||||
await updateCollection({
|
await updateCollection.mutateAsync({
|
||||||
...movedCollection,
|
...movedCollection,
|
||||||
parentId:
|
parentId:
|
||||||
destination.parentId && destination.parentId !== "root"
|
destination.parentId && destination.parentId !== "root"
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import useCollectionStore from "@/store/collections";
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { styles } from "./styles";
|
import { styles } from "./styles";
|
||||||
import { Options } from "./types";
|
import { Options } from "./types";
|
||||||
import CreatableSelect from "react-select/creatable";
|
import CreatableSelect from "react-select/creatable";
|
||||||
import Select from "react-select";
|
import Select from "react-select";
|
||||||
|
import { useCollections } from "@/hooks/store/collections";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onChange: any;
|
onChange: any;
|
||||||
|
@ -24,7 +24,9 @@ export default function CollectionSelection({
|
||||||
showDefaultValue = true,
|
showDefaultValue = true,
|
||||||
creatable = true,
|
creatable = true,
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const { collections } = useCollectionStore();
|
const { data: { response: collections } = { response: [] } } =
|
||||||
|
useCollections();
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const [options, setOptions] = useState<Options[]>([]);
|
const [options, setOptions] = useState<Options[]>([]);
|
||||||
|
|
|
@ -5,7 +5,6 @@ import {
|
||||||
} from "@/types/global";
|
} from "@/types/global";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import useLinkStore from "@/store/links";
|
import useLinkStore from "@/store/links";
|
||||||
import useCollectionStore from "@/store/collections";
|
|
||||||
import unescapeString from "@/lib/client/unescapeString";
|
import unescapeString from "@/lib/client/unescapeString";
|
||||||
import LinkActions from "@/components/LinkViews/LinkComponents/LinkActions";
|
import LinkActions from "@/components/LinkViews/LinkComponents/LinkActions";
|
||||||
import LinkDate from "@/components/LinkViews/LinkComponents/LinkDate";
|
import LinkDate from "@/components/LinkViews/LinkComponents/LinkDate";
|
||||||
|
@ -21,6 +20,7 @@ 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";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
link: LinkIncludingShortenedCollectionAndTags;
|
link: LinkIncludingShortenedCollectionAndTags;
|
||||||
|
@ -34,7 +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 { collections } = useCollectionStore();
|
const { data: { response: collections } = { response: [] } } =
|
||||||
|
useCollections();
|
||||||
|
|
||||||
const { account } = useAccountStore();
|
const { account } = useAccountStore();
|
||||||
|
|
||||||
const { links, getLink, setSelectedLinks, selectedLinks } = useLinkStore();
|
const { links, getLink, setSelectedLinks, selectedLinks } = useLinkStore();
|
||||||
|
|
|
@ -4,7 +4,6 @@ import {
|
||||||
} from "@/types/global";
|
} from "@/types/global";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import useLinkStore from "@/store/links";
|
import useLinkStore from "@/store/links";
|
||||||
import useCollectionStore from "@/store/collections";
|
|
||||||
import unescapeString from "@/lib/client/unescapeString";
|
import unescapeString from "@/lib/client/unescapeString";
|
||||||
import LinkActions from "@/components/LinkViews/LinkComponents/LinkActions";
|
import LinkActions from "@/components/LinkViews/LinkComponents/LinkActions";
|
||||||
import LinkDate from "@/components/LinkViews/LinkComponents/LinkDate";
|
import LinkDate from "@/components/LinkViews/LinkComponents/LinkDate";
|
||||||
|
@ -17,6 +16,7 @@ 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";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
link: LinkIncludingShortenedCollectionAndTags;
|
link: LinkIncludingShortenedCollectionAndTags;
|
||||||
|
@ -33,7 +33,9 @@ export default function LinkCardCompact({
|
||||||
}: Props) {
|
}: Props) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const { collections } = useCollectionStore();
|
const { data: { response: collections } = { response: [] } } =
|
||||||
|
useCollections();
|
||||||
|
|
||||||
const { account } = useAccountStore();
|
const { account } = useAccountStore();
|
||||||
const { links, setSelectedLinks, selectedLinks } = useLinkStore();
|
const { links, setSelectedLinks, selectedLinks } = useLinkStore();
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ import {
|
||||||
} from "@/types/global";
|
} from "@/types/global";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import useLinkStore from "@/store/links";
|
import useLinkStore from "@/store/links";
|
||||||
import useCollectionStore from "@/store/collections";
|
|
||||||
import unescapeString from "@/lib/client/unescapeString";
|
import unescapeString from "@/lib/client/unescapeString";
|
||||||
import LinkActions from "@/components/LinkViews/LinkComponents/LinkActions";
|
import LinkActions from "@/components/LinkViews/LinkComponents/LinkActions";
|
||||||
import LinkDate from "@/components/LinkViews/LinkComponents/LinkDate";
|
import LinkDate from "@/components/LinkViews/LinkComponents/LinkDate";
|
||||||
|
@ -21,6 +20,7 @@ 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";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
link: LinkIncludingShortenedCollectionAndTags;
|
link: LinkIncludingShortenedCollectionAndTags;
|
||||||
|
@ -33,7 +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 { collections } = useCollectionStore();
|
const { data: { response: collections } = { response: [] } } =
|
||||||
|
useCollections();
|
||||||
const { account } = useAccountStore();
|
const { account } = useAccountStore();
|
||||||
|
|
||||||
const { links, getLink, setSelectedLinks, selectedLinks } = useLinkStore();
|
const { links, getLink, setSelectedLinks, selectedLinks } = useLinkStore();
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import TextInput from "@/components/TextInput";
|
import TextInput from "@/components/TextInput";
|
||||||
import useCollectionStore from "@/store/collections";
|
|
||||||
import toast from "react-hot-toast";
|
|
||||||
import { CollectionIncludingMembersAndLinkCount } from "@/types/global";
|
import { CollectionIncludingMembersAndLinkCount } from "@/types/global";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import usePermissions from "@/hooks/usePermissions";
|
import usePermissions from "@/hooks/usePermissions";
|
||||||
import Modal from "../Modal";
|
import Modal from "../Modal";
|
||||||
import Button from "../ui/Button";
|
import Button from "../ui/Button";
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
|
import { useDeleteCollection } from "@/hooks/store/collections";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onClose: Function;
|
onClose: Function;
|
||||||
|
@ -22,7 +21,6 @@ export default function DeleteCollectionModal({
|
||||||
const [collection, setCollection] =
|
const [collection, setCollection] =
|
||||||
useState<CollectionIncludingMembersAndLinkCount>(activeCollection);
|
useState<CollectionIncludingMembersAndLinkCount>(activeCollection);
|
||||||
const [submitLoader, setSubmitLoader] = useState(false);
|
const [submitLoader, setSubmitLoader] = useState(false);
|
||||||
const { removeCollection } = useCollectionStore();
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [inputField, setInputField] = useState("");
|
const [inputField, setInputField] = useState("");
|
||||||
const permissions = usePermissions(collection.id as number);
|
const permissions = usePermissions(collection.id as number);
|
||||||
|
@ -31,6 +29,8 @@ export default function DeleteCollectionModal({
|
||||||
setCollection(activeCollection);
|
setCollection(activeCollection);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const deleteCollection = useDeleteCollection();
|
||||||
|
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
if (permissions === true && collection.name !== inputField) return;
|
if (permissions === true && collection.name !== inputField) return;
|
||||||
if (!submitLoader) {
|
if (!submitLoader) {
|
||||||
|
@ -39,19 +39,12 @@ export default function DeleteCollectionModal({
|
||||||
|
|
||||||
setSubmitLoader(true);
|
setSubmitLoader(true);
|
||||||
|
|
||||||
const load = toast.loading(t("deleting_collection"));
|
deleteCollection.mutateAsync(collection.id as number, {
|
||||||
|
onSuccess: () => {
|
||||||
let response = await removeCollection(collection.id as number);
|
|
||||||
|
|
||||||
toast.dismiss(load);
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
toast.success(t("deleted"));
|
|
||||||
onClose();
|
onClose();
|
||||||
router.push("/collections");
|
router.push("/collections");
|
||||||
} else {
|
},
|
||||||
toast.error(response.data as string);
|
});
|
||||||
}
|
|
||||||
|
|
||||||
setSubmitLoader(false);
|
setSubmitLoader(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import TextInput from "@/components/TextInput";
|
import TextInput from "@/components/TextInput";
|
||||||
import useCollectionStore from "@/store/collections";
|
|
||||||
import toast from "react-hot-toast";
|
|
||||||
import { HexColorPicker } from "react-colorful";
|
import { HexColorPicker } from "react-colorful";
|
||||||
import { CollectionIncludingMembersAndLinkCount } from "@/types/global";
|
import { CollectionIncludingMembersAndLinkCount } from "@/types/global";
|
||||||
import Modal from "../Modal";
|
import Modal from "../Modal";
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
|
import { useUpdateCollection } from "@/hooks/store/collections";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onClose: Function;
|
onClose: Function;
|
||||||
|
@ -21,7 +20,7 @@ export default function EditCollectionModal({
|
||||||
useState<CollectionIncludingMembersAndLinkCount>(activeCollection);
|
useState<CollectionIncludingMembersAndLinkCount>(activeCollection);
|
||||||
|
|
||||||
const [submitLoader, setSubmitLoader] = useState(false);
|
const [submitLoader, setSubmitLoader] = useState(false);
|
||||||
const { updateCollection } = useCollectionStore();
|
const updateCollection = useUpdateCollection();
|
||||||
|
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
if (!submitLoader) {
|
if (!submitLoader) {
|
||||||
|
@ -30,16 +29,11 @@ export default function EditCollectionModal({
|
||||||
|
|
||||||
setSubmitLoader(true);
|
setSubmitLoader(true);
|
||||||
|
|
||||||
const load = toast.loading(t("updating_collection"));
|
await updateCollection.mutateAsync(collection, {
|
||||||
|
onSuccess: () => {
|
||||||
let response = await updateCollection(collection as any);
|
|
||||||
|
|
||||||
toast.dismiss(load);
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
toast.success(t("updated"));
|
|
||||||
onClose();
|
onClose();
|
||||||
} else toast.error(response.data as string);
|
},
|
||||||
|
});
|
||||||
|
|
||||||
setSubmitLoader(false);
|
setSubmitLoader(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import TextInput from "@/components/TextInput";
|
import TextInput from "@/components/TextInput";
|
||||||
import useCollectionStore from "@/store/collections";
|
|
||||||
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";
|
||||||
|
@ -11,6 +10,7 @@ import addMemberToCollection from "@/lib/client/addMemberToCollection";
|
||||||
import Modal from "../Modal";
|
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";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onClose: Function;
|
onClose: Function;
|
||||||
|
@ -27,7 +27,7 @@ export default function EditCollectionSharingModal({
|
||||||
useState<CollectionIncludingMembersAndLinkCount>(activeCollection);
|
useState<CollectionIncludingMembersAndLinkCount>(activeCollection);
|
||||||
|
|
||||||
const [submitLoader, setSubmitLoader] = useState(false);
|
const [submitLoader, setSubmitLoader] = useState(false);
|
||||||
const { updateCollection } = useCollectionStore();
|
const updateCollection = useUpdateCollection();
|
||||||
|
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
if (!submitLoader) {
|
if (!submitLoader) {
|
||||||
|
@ -36,18 +36,11 @@ export default function EditCollectionSharingModal({
|
||||||
|
|
||||||
setSubmitLoader(true);
|
setSubmitLoader(true);
|
||||||
|
|
||||||
const load = toast.loading(t("updating"));
|
await updateCollection.mutateAsync(collection, {
|
||||||
|
onSuccess: () => {
|
||||||
let response;
|
|
||||||
|
|
||||||
response = await updateCollection(collection as any);
|
|
||||||
|
|
||||||
toast.dismiss(load);
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
toast.success(t("updated"));
|
|
||||||
onClose();
|
onClose();
|
||||||
} else toast.error(response.data as string);
|
},
|
||||||
|
});
|
||||||
|
|
||||||
setSubmitLoader(false);
|
setSubmitLoader(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import TextInput from "@/components/TextInput";
|
import TextInput from "@/components/TextInput";
|
||||||
import useCollectionStore from "@/store/collections";
|
|
||||||
import toast from "react-hot-toast";
|
|
||||||
import { HexColorPicker } from "react-colorful";
|
import { HexColorPicker } from "react-colorful";
|
||||||
import { Collection } from "@prisma/client";
|
import { Collection } from "@prisma/client";
|
||||||
import Modal from "../Modal";
|
import Modal from "../Modal";
|
||||||
|
@ -9,6 +7,7 @@ import { CollectionIncludingMembersAndLinkCount } from "@/types/global";
|
||||||
import useAccountStore from "@/store/account";
|
import useAccountStore from "@/store/account";
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
|
import { useCreateCollection } from "@/hooks/store/collections";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onClose: Function;
|
onClose: Function;
|
||||||
|
@ -33,7 +32,8 @@ export default function NewCollectionModal({ onClose, parent }: Props) {
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const [submitLoader, setSubmitLoader] = useState(false);
|
const [submitLoader, setSubmitLoader] = useState(false);
|
||||||
const { addCollection } = useCollectionStore();
|
|
||||||
|
const createCollection = useCreateCollection();
|
||||||
|
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
if (submitLoader) return;
|
if (submitLoader) return;
|
||||||
|
@ -41,18 +41,11 @@ export default function NewCollectionModal({ onClose, parent }: Props) {
|
||||||
|
|
||||||
setSubmitLoader(true);
|
setSubmitLoader(true);
|
||||||
|
|
||||||
const load = toast.loading(t("creating"));
|
await createCollection.mutateAsync(collection, {
|
||||||
|
onSuccess: () => {
|
||||||
let response = await addCollection(collection as any);
|
|
||||||
toast.dismiss(load);
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
toast.success(t("created_success"));
|
|
||||||
if (response.data) {
|
|
||||||
setAccount(data?.user.id as number);
|
|
||||||
onClose();
|
onClose();
|
||||||
}
|
},
|
||||||
} else toast.error(response.data as string);
|
});
|
||||||
|
|
||||||
setSubmitLoader(false);
|
setSubmitLoader(false);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { Toaster } from "react-hot-toast";
|
|
||||||
import CollectionSelection from "@/components/InputSelect/CollectionSelection";
|
import CollectionSelection from "@/components/InputSelect/CollectionSelection";
|
||||||
import TagSelection from "@/components/InputSelect/TagSelection";
|
import TagSelection from "@/components/InputSelect/TagSelection";
|
||||||
import TextInput from "@/components/TextInput";
|
import TextInput from "@/components/TextInput";
|
||||||
import unescapeString from "@/lib/client/unescapeString";
|
import unescapeString from "@/lib/client/unescapeString";
|
||||||
import useCollectionStore from "@/store/collections";
|
|
||||||
import useLinkStore from "@/store/links";
|
import useLinkStore from "@/store/links";
|
||||||
import { LinkIncludingShortenedCollectionAndTags } from "@/types/global";
|
import { LinkIncludingShortenedCollectionAndTags } from "@/types/global";
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
|
@ -12,6 +10,7 @@ import { useRouter } from "next/router";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import Modal from "../Modal";
|
import Modal from "../Modal";
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
|
import { useCollections } from "@/hooks/store/collections";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onClose: Function;
|
onClose: Function;
|
||||||
|
@ -44,7 +43,8 @@ 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 { collections } = useCollectionStore();
|
const { data: { response: collections } = { response: [] } } =
|
||||||
|
useCollections();
|
||||||
|
|
||||||
const setCollection = (e: any) => {
|
const setCollection = (e: any) => {
|
||||||
if (e?.__isNew__) e.value = null;
|
if (e?.__isNew__) e.value = null;
|
||||||
|
|
|
@ -3,7 +3,6 @@ import CollectionSelection from "@/components/InputSelect/CollectionSelection";
|
||||||
import TagSelection from "@/components/InputSelect/TagSelection";
|
import TagSelection from "@/components/InputSelect/TagSelection";
|
||||||
import TextInput from "@/components/TextInput";
|
import TextInput from "@/components/TextInput";
|
||||||
import unescapeString from "@/lib/client/unescapeString";
|
import unescapeString from "@/lib/client/unescapeString";
|
||||||
import useCollectionStore from "@/store/collections";
|
|
||||||
import useLinkStore from "@/store/links";
|
import useLinkStore from "@/store/links";
|
||||||
import {
|
import {
|
||||||
LinkIncludingShortenedCollectionAndTags,
|
LinkIncludingShortenedCollectionAndTags,
|
||||||
|
@ -14,6 +13,7 @@ import { useRouter } from "next/router";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import Modal from "../Modal";
|
import Modal from "../Modal";
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
|
import { useCollections } from "@/hooks/store/collections";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
onClose: Function;
|
onClose: Function;
|
||||||
|
@ -49,7 +49,8 @@ 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 { collections } = useCollectionStore();
|
const { data: { response: collections } = { response: [] } } =
|
||||||
|
useCollections();
|
||||||
|
|
||||||
const setCollection = (e: any) => {
|
const setCollection = (e: any) => {
|
||||||
if (e?.__isNew__) e.value = null;
|
if (e?.__isNew__) e.value = null;
|
||||||
|
|
|
@ -14,8 +14,8 @@ import Link from "next/link";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import React, { useEffect, useMemo, useState } from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
import LinkActions from "./LinkViews/LinkComponents/LinkActions";
|
import LinkActions from "./LinkViews/LinkComponents/LinkActions";
|
||||||
import useCollectionStore from "@/store/collections";
|
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
|
import { useCollections } from "@/hooks/store/collections";
|
||||||
|
|
||||||
type LinkContent = {
|
type LinkContent = {
|
||||||
title: string;
|
title: string;
|
||||||
|
@ -46,7 +46,8 @@ export default function ReadableView({ link }: Props) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const { getLink } = useLinkStore();
|
const { getLink } = useLinkStore();
|
||||||
const { collections } = useCollectionStore();
|
const { data: { response: collections } = { response: [] } } =
|
||||||
|
useCollections();
|
||||||
|
|
||||||
const collection = useMemo(() => {
|
const collection = useMemo(() => {
|
||||||
return collections.find(
|
return collections.find(
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import useCollectionStore from "@/store/collections";
|
|
||||||
import useTagStore from "@/store/tags";
|
import useTagStore from "@/store/tags";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
@ -7,6 +6,7 @@ import { Disclosure, Transition } from "@headlessui/react";
|
||||||
import SidebarHighlightLink from "@/components/SidebarHighlightLink";
|
import SidebarHighlightLink from "@/components/SidebarHighlightLink";
|
||||||
import CollectionListing from "@/components/CollectionListing";
|
import CollectionListing from "@/components/CollectionListing";
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
|
import { useCollections } from "@/hooks/store/collections";
|
||||||
|
|
||||||
export default function Sidebar({ className }: { className?: string }) {
|
export default function Sidebar({ className }: { className?: string }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -22,7 +22,9 @@ export default function Sidebar({ className }: { className?: string }) {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const { collections } = useCollectionStore();
|
const { data: { response: collections } = { response: [] } } =
|
||||||
|
useCollections();
|
||||||
|
|
||||||
const { tags } = useTagStore();
|
const { tags } = useTagStore();
|
||||||
const [active, setActive] = useState("");
|
const [active, setActive] = useState("");
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,272 @@
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
className?: string;
|
||||||
|
color: string;
|
||||||
|
size: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Loader = (props: Props) => {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 100 100"
|
||||||
|
preserveAspectRatio="xMidYMid"
|
||||||
|
width={props.size}
|
||||||
|
height={props.size}
|
||||||
|
className={props.className}
|
||||||
|
style={{
|
||||||
|
shapeRendering: "auto",
|
||||||
|
display: "block",
|
||||||
|
background: "rgba(255, 255, 255, 0)",
|
||||||
|
}}
|
||||||
|
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||||
|
>
|
||||||
|
<g>
|
||||||
|
<g transform="rotate(0 50 50)">
|
||||||
|
<rect
|
||||||
|
fill={props.color}
|
||||||
|
height="12"
|
||||||
|
width="6"
|
||||||
|
ry="1.8"
|
||||||
|
rx="1.8"
|
||||||
|
y="24"
|
||||||
|
x="47"
|
||||||
|
>
|
||||||
|
<animate
|
||||||
|
repeatCount="indefinite"
|
||||||
|
begin="-0.9166666666666666s"
|
||||||
|
dur="1s"
|
||||||
|
keyTimes="0;1"
|
||||||
|
values="1;0"
|
||||||
|
attributeName="opacity"
|
||||||
|
></animate>
|
||||||
|
</rect>
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(30 50 50)">
|
||||||
|
<rect
|
||||||
|
fill={props.color}
|
||||||
|
height="12"
|
||||||
|
width="6"
|
||||||
|
ry="1.8"
|
||||||
|
rx="1.8"
|
||||||
|
y="24"
|
||||||
|
x="47"
|
||||||
|
>
|
||||||
|
<animate
|
||||||
|
repeatCount="indefinite"
|
||||||
|
begin="-0.8333333333333334s"
|
||||||
|
dur="1s"
|
||||||
|
keyTimes="0;1"
|
||||||
|
values="1;0"
|
||||||
|
attributeName="opacity"
|
||||||
|
></animate>
|
||||||
|
</rect>
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(60 50 50)">
|
||||||
|
<rect
|
||||||
|
fill={props.color}
|
||||||
|
height="12"
|
||||||
|
width="6"
|
||||||
|
ry="1.8"
|
||||||
|
rx="1.8"
|
||||||
|
y="24"
|
||||||
|
x="47"
|
||||||
|
>
|
||||||
|
<animate
|
||||||
|
repeatCount="indefinite"
|
||||||
|
begin="-0.75s"
|
||||||
|
dur="1s"
|
||||||
|
keyTimes="0;1"
|
||||||
|
values="1;0"
|
||||||
|
attributeName="opacity"
|
||||||
|
></animate>
|
||||||
|
</rect>
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(90 50 50)">
|
||||||
|
<rect
|
||||||
|
fill={props.color}
|
||||||
|
height="12"
|
||||||
|
width="6"
|
||||||
|
ry="1.8"
|
||||||
|
rx="1.8"
|
||||||
|
y="24"
|
||||||
|
x="47"
|
||||||
|
>
|
||||||
|
<animate
|
||||||
|
repeatCount="indefinite"
|
||||||
|
begin="-0.6666666666666666s"
|
||||||
|
dur="1s"
|
||||||
|
keyTimes="0;1"
|
||||||
|
values="1;0"
|
||||||
|
attributeName="opacity"
|
||||||
|
></animate>
|
||||||
|
</rect>
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(120 50 50)">
|
||||||
|
<rect
|
||||||
|
fill={props.color}
|
||||||
|
height="12"
|
||||||
|
width="6"
|
||||||
|
ry="1.8"
|
||||||
|
rx="1.8"
|
||||||
|
y="24"
|
||||||
|
x="47"
|
||||||
|
>
|
||||||
|
<animate
|
||||||
|
repeatCount="indefinite"
|
||||||
|
begin="-0.5833333333333334s"
|
||||||
|
dur="1s"
|
||||||
|
keyTimes="0;1"
|
||||||
|
values="1;0"
|
||||||
|
attributeName="opacity"
|
||||||
|
></animate>
|
||||||
|
</rect>
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(150 50 50)">
|
||||||
|
<rect
|
||||||
|
fill={props.color}
|
||||||
|
height="12"
|
||||||
|
width="6"
|
||||||
|
ry="1.8"
|
||||||
|
rx="1.8"
|
||||||
|
y="24"
|
||||||
|
x="47"
|
||||||
|
>
|
||||||
|
<animate
|
||||||
|
repeatCount="indefinite"
|
||||||
|
begin="-0.5s"
|
||||||
|
dur="1s"
|
||||||
|
keyTimes="0;1"
|
||||||
|
values="1;0"
|
||||||
|
attributeName="opacity"
|
||||||
|
></animate>
|
||||||
|
</rect>
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(180 50 50)">
|
||||||
|
<rect
|
||||||
|
fill={props.color}
|
||||||
|
height="12"
|
||||||
|
width="6"
|
||||||
|
ry="1.8"
|
||||||
|
rx="1.8"
|
||||||
|
y="24"
|
||||||
|
x="47"
|
||||||
|
>
|
||||||
|
<animate
|
||||||
|
repeatCount="indefinite"
|
||||||
|
begin="-0.4166666666666667s"
|
||||||
|
dur="1s"
|
||||||
|
keyTimes="0;1"
|
||||||
|
values="1;0"
|
||||||
|
attributeName="opacity"
|
||||||
|
></animate>
|
||||||
|
</rect>
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(210 50 50)">
|
||||||
|
<rect
|
||||||
|
fill={props.color}
|
||||||
|
height="12"
|
||||||
|
width="6"
|
||||||
|
ry="1.8"
|
||||||
|
rx="1.8"
|
||||||
|
y="24"
|
||||||
|
x="47"
|
||||||
|
>
|
||||||
|
<animate
|
||||||
|
repeatCount="indefinite"
|
||||||
|
begin="-0.3333333333333333s"
|
||||||
|
dur="1s"
|
||||||
|
keyTimes="0;1"
|
||||||
|
values="1;0"
|
||||||
|
attributeName="opacity"
|
||||||
|
></animate>
|
||||||
|
</rect>
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(240 50 50)">
|
||||||
|
<rect
|
||||||
|
fill={props.color}
|
||||||
|
height="12"
|
||||||
|
width="6"
|
||||||
|
ry="1.8"
|
||||||
|
rx="1.8"
|
||||||
|
y="24"
|
||||||
|
x="47"
|
||||||
|
>
|
||||||
|
<animate
|
||||||
|
repeatCount="indefinite"
|
||||||
|
begin="-0.25s"
|
||||||
|
dur="1s"
|
||||||
|
keyTimes="0;1"
|
||||||
|
values="1;0"
|
||||||
|
attributeName="opacity"
|
||||||
|
></animate>
|
||||||
|
</rect>
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(270 50 50)">
|
||||||
|
<rect
|
||||||
|
fill={props.color}
|
||||||
|
height="12"
|
||||||
|
width="6"
|
||||||
|
ry="1.8"
|
||||||
|
rx="1.8"
|
||||||
|
y="24"
|
||||||
|
x="47"
|
||||||
|
>
|
||||||
|
<animate
|
||||||
|
repeatCount="indefinite"
|
||||||
|
begin="-0.16666666666666666s"
|
||||||
|
dur="1s"
|
||||||
|
keyTimes="0;1"
|
||||||
|
values="1;0"
|
||||||
|
attributeName="opacity"
|
||||||
|
></animate>
|
||||||
|
</rect>
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(300 50 50)">
|
||||||
|
<rect
|
||||||
|
fill={props.color}
|
||||||
|
height="12"
|
||||||
|
width="6"
|
||||||
|
ry="1.8"
|
||||||
|
rx="1.8"
|
||||||
|
y="24"
|
||||||
|
x="47"
|
||||||
|
>
|
||||||
|
<animate
|
||||||
|
repeatCount="indefinite"
|
||||||
|
begin="-0.08333333333333333s"
|
||||||
|
dur="1s"
|
||||||
|
keyTimes="0;1"
|
||||||
|
values="1;0"
|
||||||
|
attributeName="opacity"
|
||||||
|
></animate>
|
||||||
|
</rect>
|
||||||
|
</g>
|
||||||
|
<g transform="rotate(330 50 50)">
|
||||||
|
<rect
|
||||||
|
fill={props.color}
|
||||||
|
height="12"
|
||||||
|
width="6"
|
||||||
|
ry="1.8"
|
||||||
|
rx="1.8"
|
||||||
|
y="24"
|
||||||
|
x="47"
|
||||||
|
>
|
||||||
|
<animate
|
||||||
|
repeatCount="indefinite"
|
||||||
|
begin="0s"
|
||||||
|
dur="1s"
|
||||||
|
keyTimes="0;1"
|
||||||
|
values="1;0"
|
||||||
|
attributeName="opacity"
|
||||||
|
></animate>
|
||||||
|
</rect>
|
||||||
|
</g>
|
||||||
|
<g></g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Loader;
|
|
@ -0,0 +1,131 @@
|
||||||
|
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||||
|
import { CollectionIncludingMembersAndLinkCount } from "@/types/global";
|
||||||
|
import { useTranslation } from "next-i18next";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
|
|
||||||
|
const useCollections = () => {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ["collections"],
|
||||||
|
queryFn: async (): Promise<{
|
||||||
|
response: CollectionIncludingMembersAndLinkCount[];
|
||||||
|
}> => {
|
||||||
|
const response = await fetch("/api/v1/collections");
|
||||||
|
const data = await response.json();
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const useCreateCollection = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: async (data: any) => {
|
||||||
|
const load = toast.loading(t("creating"));
|
||||||
|
|
||||||
|
const response = await fetch("/api/v1/collections", {
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
method: "POST",
|
||||||
|
});
|
||||||
|
|
||||||
|
toast.dismiss(load);
|
||||||
|
|
||||||
|
return response.json();
|
||||||
|
},
|
||||||
|
onSuccess: (data) => {
|
||||||
|
toast.success(t("created"));
|
||||||
|
return queryClient.setQueryData(["collections"], (oldData: any) => {
|
||||||
|
return {
|
||||||
|
response: [...oldData.response, data.response],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
toast.error(error.message);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const useUpdateCollection = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: async (data: any) => {
|
||||||
|
const load = toast.loading(t("updating_collection"));
|
||||||
|
|
||||||
|
const response = await fetch(`/api/v1/collections/${data.id}`, {
|
||||||
|
method: "PUT",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(data),
|
||||||
|
});
|
||||||
|
|
||||||
|
toast.dismiss(load);
|
||||||
|
|
||||||
|
return response.json();
|
||||||
|
},
|
||||||
|
onSuccess: (data) => {
|
||||||
|
{
|
||||||
|
toast.success(t("updated"));
|
||||||
|
return queryClient.setQueryData(["collections"], (oldData: any) => {
|
||||||
|
return {
|
||||||
|
response: oldData.response.map((collection: any) =>
|
||||||
|
collection.id === data.response.id ? data.response : collection
|
||||||
|
),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
toast.error(error.message);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const useDeleteCollection = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: async (id: number) => {
|
||||||
|
const load = toast.loading(t("deleting_collection"));
|
||||||
|
|
||||||
|
const response = await fetch(`/api/v1/collections/${id}`, {
|
||||||
|
method: "DELETE",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
toast.dismiss(load);
|
||||||
|
|
||||||
|
return response.json();
|
||||||
|
},
|
||||||
|
onSuccess: (data) => {
|
||||||
|
toast.success(t("deleted"));
|
||||||
|
return queryClient.setQueryData(["collections"], (oldData: any) => {
|
||||||
|
return {
|
||||||
|
response: oldData.response.filter(
|
||||||
|
(collection: any) => collection.id !== data.response.id
|
||||||
|
),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
toast.error(error.message);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
useCollections,
|
||||||
|
useCreateCollection,
|
||||||
|
useUpdateCollection,
|
||||||
|
useDeleteCollection,
|
||||||
|
};
|
|
@ -1,10 +1,11 @@
|
||||||
import useAccountStore from "@/store/account";
|
import useAccountStore from "@/store/account";
|
||||||
import useCollectionStore from "@/store/collections";
|
|
||||||
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";
|
||||||
|
|
||||||
export default function useCollectivePermissions(collectionIds: number[]) {
|
export default function useCollectivePermissions(collectionIds: number[]) {
|
||||||
const { collections } = useCollectionStore();
|
const { data: { response: collections } = { response: [] } } =
|
||||||
|
useCollections();
|
||||||
|
|
||||||
const { account } = useAccountStore();
|
const { account } = useAccountStore();
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import useCollectionStore from "@/store/collections";
|
|
||||||
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";
|
||||||
|
@ -7,7 +6,7 @@ import useLocalSettingsStore from "@/store/localSettings";
|
||||||
|
|
||||||
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 { account, setAccount } = useAccountStore();
|
||||||
|
@ -24,7 +23,7 @@ export default function useInitialData() {
|
||||||
// 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 (account.id && (!process.env.NEXT_PUBLIC_STRIPE || account.username)) {
|
||||||
setCollections();
|
// setCollections();
|
||||||
setTags();
|
setTags();
|
||||||
// setLinks();
|
// setLinks();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import useAccountStore from "@/store/account";
|
import useAccountStore from "@/store/account";
|
||||||
import useCollectionStore from "@/store/collections";
|
|
||||||
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";
|
||||||
|
|
||||||
export default function usePermissions(collectionId: number) {
|
export default function usePermissions(collectionId: number) {
|
||||||
const { collections } = useCollectionStore();
|
const { data: { response: collections } = { response: [] } } =
|
||||||
|
useCollections();
|
||||||
|
|
||||||
const { account } = useAccountStore();
|
const { account } = useAccountStore();
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
"@mozilla/readability": "^0.4.4",
|
"@mozilla/readability": "^0.4.4",
|
||||||
"@prisma/client": "^4.16.2",
|
"@prisma/client": "^4.16.2",
|
||||||
"@stripe/stripe-js": "^1.54.1",
|
"@stripe/stripe-js": "^1.54.1",
|
||||||
|
"@tanstack/react-query": "^5.51.15",
|
||||||
|
"@tanstack/react-query-devtools": "^5.51.15",
|
||||||
"@types/crypto-js": "^4.1.1",
|
"@types/crypto-js": "^4.1.1",
|
||||||
"@types/formidable": "^3.4.5",
|
"@types/formidable": "^3.4.5",
|
||||||
"@types/node": "^20.10.4",
|
"@types/node": "^20.10.4",
|
||||||
|
|
|
@ -11,7 +11,10 @@ import { Session } from "next-auth";
|
||||||
import { isPWA } from "@/lib/client/utils";
|
import { isPWA } from "@/lib/client/utils";
|
||||||
// import useInitialData from "@/hooks/useInitialData";
|
// import useInitialData from "@/hooks/useInitialData";
|
||||||
import { appWithTranslation } from "next-i18next";
|
import { appWithTranslation } from "next-i18next";
|
||||||
import nextI18nextConfig from "../next-i18next.config";
|
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
|
||||||
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
|
|
||||||
|
const queryClient = new QueryClient();
|
||||||
|
|
||||||
function App({
|
function App({
|
||||||
Component,
|
Component,
|
||||||
|
@ -29,6 +32,7 @@ function App({
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<QueryClientProvider client={queryClient}>
|
||||||
<SessionProvider
|
<SessionProvider
|
||||||
session={pageProps.session}
|
session={pageProps.session}
|
||||||
refetchOnWindowFocus={false}
|
refetchOnWindowFocus={false}
|
||||||
|
@ -95,6 +99,8 @@ function App({
|
||||||
{/* </GetData> */}
|
{/* </GetData> */}
|
||||||
</AuthRedirect>
|
</AuthRedirect>
|
||||||
</SessionProvider>
|
</SessionProvider>
|
||||||
|
<ReactQueryDevtools initialIsOpen={false} />
|
||||||
|
</QueryClientProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import useCollectionStore from "@/store/collections";
|
|
||||||
import useLinkStore from "@/store/links";
|
import useLinkStore from "@/store/links";
|
||||||
import {
|
import {
|
||||||
CollectionIncludingMembersAndLinkCount,
|
CollectionIncludingMembersAndLinkCount,
|
||||||
|
@ -26,6 +25,7 @@ import MasonryView from "@/components/LinkViews/Layouts/MasonryView";
|
||||||
import getServerSideProps from "@/lib/client/getServerSideProps";
|
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";
|
||||||
|
|
||||||
export default function Index() {
|
export default function Index() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -34,7 +34,8 @@ export default function Index() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const { links } = useLinkStore();
|
const { links } = useLinkStore();
|
||||||
const { collections } = useCollectionStore();
|
const { data: { response: collections } = { response: [] } } =
|
||||||
|
useCollections();
|
||||||
|
|
||||||
const [sortBy, setSortBy] = useState<Sort>(Sort.DateNewestFirst);
|
const [sortBy, setSortBy] = useState<Sort>(Sort.DateNewestFirst);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import useCollectionStore from "@/store/collections";
|
|
||||||
import CollectionCard from "@/components/CollectionCard";
|
import CollectionCard from "@/components/CollectionCard";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import MainLayout from "@/layouts/MainLayout";
|
import MainLayout from "@/layouts/MainLayout";
|
||||||
|
@ -10,10 +9,12 @@ import NewCollectionModal from "@/components/ModalContent/NewCollectionModal";
|
||||||
import PageHeader from "@/components/PageHeader";
|
import PageHeader from "@/components/PageHeader";
|
||||||
import getServerSideProps from "@/lib/client/getServerSideProps";
|
import getServerSideProps from "@/lib/client/getServerSideProps";
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
|
import { useCollections } from "@/hooks/store/collections";
|
||||||
|
|
||||||
export default function Collections() {
|
export default function Collections() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { collections } = useCollectionStore();
|
const { data: { response: collections } = { response: [] } } =
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import useLinkStore from "@/store/links";
|
import useLinkStore from "@/store/links";
|
||||||
import useCollectionStore from "@/store/collections";
|
|
||||||
import useTagStore from "@/store/tags";
|
import useTagStore from "@/store/tags";
|
||||||
import MainLayout from "@/layouts/MainLayout";
|
import MainLayout from "@/layouts/MainLayout";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
@ -19,10 +18,12 @@ import { dropdownTriggerer } from "@/lib/client/utils";
|
||||||
import MasonryView from "@/components/LinkViews/Layouts/MasonryView";
|
import MasonryView from "@/components/LinkViews/Layouts/MasonryView";
|
||||||
import getServerSideProps from "@/lib/client/getServerSideProps";
|
import getServerSideProps from "@/lib/client/getServerSideProps";
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
|
import { useCollections } from "@/hooks/store/collections";
|
||||||
|
|
||||||
export default function Dashboard() {
|
export default function Dashboard() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { collections } = useCollectionStore();
|
const { data: { response: collections } = { response: [] } } =
|
||||||
|
useCollections();
|
||||||
const { links } = useLinkStore();
|
const { links } = useLinkStore();
|
||||||
const { tags } = useTagStore();
|
const { tags } = useTagStore();
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,8 @@ import ListView from "@/components/LinkViews/Layouts/ListView";
|
||||||
import MasonryView from "@/components/LinkViews/Layouts/MasonryView";
|
import MasonryView from "@/components/LinkViews/Layouts/MasonryView";
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
import getServerSideProps from "@/lib/client/getServerSideProps";
|
import getServerSideProps from "@/lib/client/getServerSideProps";
|
||||||
import useCollectionStore from "@/store/collections";
|
|
||||||
import LinkListOptions from "@/components/LinkListOptions";
|
import LinkListOptions from "@/components/LinkListOptions";
|
||||||
|
import { useCollections } from "@/hooks/store/collections";
|
||||||
|
|
||||||
export default function PublicCollections() {
|
export default function PublicCollections() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -32,7 +32,8 @@ export default function PublicCollections() {
|
||||||
|
|
||||||
const { settings } = useLocalSettingsStore();
|
const { settings } = useLocalSettingsStore();
|
||||||
|
|
||||||
const { collections } = useCollectionStore();
|
const { data: { response: collections } = { response: [] } } =
|
||||||
|
useCollections();
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
|
@ -1,94 +0,0 @@
|
||||||
import { create } from "zustand";
|
|
||||||
import { CollectionIncludingMembersAndLinkCount } from "@/types/global";
|
|
||||||
import useTagStore from "./tags";
|
|
||||||
|
|
||||||
type ResponseObject = {
|
|
||||||
ok: boolean;
|
|
||||||
data: object | string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type CollectionStore = {
|
|
||||||
collections: CollectionIncludingMembersAndLinkCount[];
|
|
||||||
setCollections: () => void;
|
|
||||||
addCollection: (
|
|
||||||
body: CollectionIncludingMembersAndLinkCount
|
|
||||||
) => Promise<ResponseObject>;
|
|
||||||
updateCollection: (
|
|
||||||
collection: CollectionIncludingMembersAndLinkCount
|
|
||||||
) => Promise<ResponseObject>;
|
|
||||||
removeCollection: (collectionId: number) => Promise<ResponseObject>;
|
|
||||||
};
|
|
||||||
|
|
||||||
const useCollectionStore = create<CollectionStore>()((set) => ({
|
|
||||||
collections: [],
|
|
||||||
setCollections: async () => {
|
|
||||||
const response = await fetch("/api/v1/collections");
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
if (response.ok) set({ collections: data.response });
|
|
||||||
},
|
|
||||||
addCollection: async (body) => {
|
|
||||||
const response = await fetch("/api/v1/collections", {
|
|
||||||
body: JSON.stringify(body),
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
if (response.ok)
|
|
||||||
set((state) => ({
|
|
||||||
collections: [...state.collections, data.response],
|
|
||||||
}));
|
|
||||||
|
|
||||||
return { ok: response.ok, data: data.response };
|
|
||||||
},
|
|
||||||
updateCollection: async (collection) => {
|
|
||||||
const response = await fetch(`/api/v1/collections/${collection.id}`, {
|
|
||||||
body: JSON.stringify(collection),
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
method: "PUT",
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
if (response.ok)
|
|
||||||
set((state) => ({
|
|
||||||
collections: state.collections.map((e) =>
|
|
||||||
e.id === data.response.id ? data.response : e
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
|
|
||||||
return { ok: response.ok, data: data.response };
|
|
||||||
},
|
|
||||||
removeCollection: async (collectionId) => {
|
|
||||||
const response = await fetch(`/api/v1/collections/${collectionId}`, {
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
method: "DELETE",
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
set((state) => ({
|
|
||||||
collections: state.collections.filter(
|
|
||||||
(collection) =>
|
|
||||||
collection.id !== collectionId &&
|
|
||||||
collection.parentId !== collectionId
|
|
||||||
),
|
|
||||||
}));
|
|
||||||
useTagStore.getState().setTags();
|
|
||||||
}
|
|
||||||
|
|
||||||
return { ok: response.ok, data: data.response };
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
export default useCollectionStore;
|
|
24
yarn.lock
24
yarn.lock
|
@ -1903,6 +1903,30 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib "^2.4.0"
|
tslib "^2.4.0"
|
||||||
|
|
||||||
|
"@tanstack/query-core@5.51.15":
|
||||||
|
version "5.51.15"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.51.15.tgz#7aee6a2d5d3f64de3e54096607233b1132dc6afd"
|
||||||
|
integrity sha512-xyobHDJ0yhPE3+UkSQ2/4X1fLSg7ICJI5J1JyU9yf7F3deQfEwSImCDrB1WSRrauJkMtXW7YIEcC0oA6ZZWt5A==
|
||||||
|
|
||||||
|
"@tanstack/query-devtools@5.51.15":
|
||||||
|
version "5.51.15"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tanstack/query-devtools/-/query-devtools-5.51.15.tgz#81c5c28231adc4b95fe4a5e1004020fdca5ea447"
|
||||||
|
integrity sha512-1oSCl+PsCa/aBCGVM2ZdcQLuQ0QYmKXJJB264twEMVM1M0n5CI40trtywORPF+wLGuZNIZzkKL7j/98mOLAIag==
|
||||||
|
|
||||||
|
"@tanstack/react-query-devtools@^5.51.15":
|
||||||
|
version "5.51.15"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tanstack/react-query-devtools/-/react-query-devtools-5.51.15.tgz#5c4d21305fd25c35dc88bd280304f77a45554fc2"
|
||||||
|
integrity sha512-bvGvJoncjZ3irEofoFevptj5BPkDpQrp2+dZhtFqPUZXRT6MAKPmOqtSmZPfacLR5jQLpqw/7d3Zxr173z7WDA==
|
||||||
|
dependencies:
|
||||||
|
"@tanstack/query-devtools" "5.51.15"
|
||||||
|
|
||||||
|
"@tanstack/react-query@^5.51.15":
|
||||||
|
version "5.51.15"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.51.15.tgz#059bb2966f828263adb355de81410d107e22b5bc"
|
||||||
|
integrity sha512-UgFg23SrdIYrmfTSxAUn9g+J64VQy11pb9/EefoY/u2+zWuNMeqEOnvpJhf52XQy0yztQoyM9p6x8PFyTNaxXg==
|
||||||
|
dependencies:
|
||||||
|
"@tanstack/query-core" "5.51.15"
|
||||||
|
|
||||||
"@tokenizer/token@^0.3.0":
|
"@tokenizer/token@^0.3.0":
|
||||||
version "0.3.0"
|
version "0.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/@tokenizer/token/-/token-0.3.0.tgz#fe98a93fe789247e998c75e74e9c7c63217aa276"
|
resolved "https://registry.yarnpkg.com/@tokenizer/token/-/token-0.3.0.tgz#fe98a93fe789247e998c75e74e9c7c63217aa276"
|
||||||
|
|
Ŝarĝante…
Reference in New Issue