refactored link state management + a lot of other changes...
This commit is contained in:
@@ -11,7 +11,6 @@ const useCollections = () => {
|
||||
const data = await response.json();
|
||||
return data.response;
|
||||
},
|
||||
initialData: [],
|
||||
});
|
||||
};
|
||||
|
||||
@@ -42,8 +41,6 @@ const useCreateCollection = () => {
|
||||
onSuccess: (data) => {
|
||||
toast.success(t("created"));
|
||||
return queryClient.setQueryData(["collections"], (oldData: any) => {
|
||||
console.log([...oldData, data]);
|
||||
|
||||
return [...oldData, data];
|
||||
});
|
||||
},
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { LinkIncludingShortenedCollectionAndTags } from "@/types/global";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
|
||||
const useDashboardData = () => {
|
||||
return useQuery({
|
||||
queryKey: ["dashboardData"],
|
||||
queryFn: async (): Promise<LinkIncludingShortenedCollectionAndTags[]> => {
|
||||
const response = await fetch("/api/v1/dashboard");
|
||||
const data = await response.json();
|
||||
|
||||
return data.response;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export { useDashboardData };
|
||||
@@ -0,0 +1,499 @@
|
||||
import {
|
||||
InfiniteData,
|
||||
useInfiniteQuery,
|
||||
UseInfiniteQueryResult,
|
||||
useQueryClient,
|
||||
useMutation,
|
||||
} from "@tanstack/react-query";
|
||||
import { useEffect, useMemo } from "react";
|
||||
import {
|
||||
ArchivedFormat,
|
||||
LinkIncludingShortenedCollectionAndTags,
|
||||
LinkRequestQuery,
|
||||
} from "@/types/global";
|
||||
import toast from "react-hot-toast";
|
||||
import { useTranslation } from "next-i18next";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
const useLinks = (params: LinkRequestQuery = {}) => {
|
||||
const router = useRouter();
|
||||
|
||||
const queryParamsObject = {
|
||||
sort: params.sort ?? Number(window.localStorage.getItem("sortBy")) ?? 0,
|
||||
collectionId:
|
||||
params.collectionId ?? router.pathname === "/collections/[id]"
|
||||
? router.query.id
|
||||
: undefined,
|
||||
tagId:
|
||||
params.tagId ?? router.pathname === "/tags/[id]"
|
||||
? router.query.id
|
||||
: undefined,
|
||||
pinnedOnly:
|
||||
params.pinnedOnly ?? router.pathname === "/links/pinned"
|
||||
? true
|
||||
: undefined,
|
||||
searchQueryString: params.searchQueryString,
|
||||
searchByName: params.searchByName,
|
||||
searchByUrl: params.searchByUrl,
|
||||
searchByDescription: params.searchByDescription,
|
||||
searchByTextContent: params.searchByTextContent,
|
||||
searchByTags: params.searchByTags,
|
||||
} as LinkRequestQuery;
|
||||
|
||||
const queryString = buildQueryString(queryParamsObject);
|
||||
|
||||
const { data, ...rest } = useFetchLinks(queryString);
|
||||
|
||||
const links = useMemo(() => {
|
||||
return data?.pages.reduce((acc, page) => {
|
||||
return [...acc, ...page];
|
||||
}, []);
|
||||
}, [data]);
|
||||
|
||||
return {
|
||||
links,
|
||||
data: { ...data, ...rest },
|
||||
} as {
|
||||
links: LinkIncludingShortenedCollectionAndTags[];
|
||||
data: UseInfiniteQueryResult<InfiniteData<any, unknown>, Error>;
|
||||
};
|
||||
};
|
||||
|
||||
const useFetchLinks = (params: string) => {
|
||||
return useInfiniteQuery({
|
||||
queryKey: ["links", { params }],
|
||||
queryFn: async (params) => {
|
||||
const response = await fetch(
|
||||
"/api/v1/links?cursor=" +
|
||||
params.pageParam +
|
||||
((params.queryKey[1] as any).params
|
||||
? "&" + (params.queryKey[1] as any).params
|
||||
: "")
|
||||
);
|
||||
const data = await response.json();
|
||||
|
||||
return data.response;
|
||||
},
|
||||
initialPageParam: 0,
|
||||
refetchOnWindowFocus: false,
|
||||
getNextPageParam: (lastPage) => {
|
||||
if (lastPage.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
return lastPage.at(-1).id;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const buildQueryString = (params: LinkRequestQuery) => {
|
||||
return Object.keys(params)
|
||||
.filter((key) => params[key as keyof LinkRequestQuery] !== undefined)
|
||||
.map(
|
||||
(key) =>
|
||||
`${encodeURIComponent(key)}=${encodeURIComponent(
|
||||
params[key as keyof LinkRequestQuery] as string
|
||||
)}`
|
||||
)
|
||||
.join("&");
|
||||
};
|
||||
|
||||
const useAddLink = () => {
|
||||
const { t } = useTranslation();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (link: LinkIncludingShortenedCollectionAndTags) => {
|
||||
const load = toast.loading(t("creating_link"));
|
||||
|
||||
const response = await fetch("/api/v1/links", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(link),
|
||||
});
|
||||
|
||||
toast.dismiss(load);
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) throw new Error(data.response);
|
||||
|
||||
return data.response;
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
toast.success(t("link_created"));
|
||||
|
||||
queryClient.setQueryData(["dashboardData"], (oldData: any) => {
|
||||
if (!oldData) return undefined;
|
||||
return [data, ...oldData];
|
||||
});
|
||||
|
||||
queryClient.setQueryData(["links"], (oldData: any) => {
|
||||
if (!oldData) return undefined;
|
||||
return {
|
||||
pages: [[data, ...oldData?.pages[0]], ...oldData?.pages.slice(1)],
|
||||
pageParams: oldData?.pageParams,
|
||||
};
|
||||
});
|
||||
|
||||
queryClient.invalidateQueries({ queryKey: ["collections"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["tags"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["publicLinks"] });
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(error.message);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const useUpdateLink = () => {
|
||||
const { t } = useTranslation();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (link: LinkIncludingShortenedCollectionAndTags) => {
|
||||
const load = toast.loading(t("updating"));
|
||||
|
||||
const response = await fetch(`/api/v1/links/${link.id}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(link),
|
||||
});
|
||||
|
||||
toast.dismiss(load);
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) throw new Error(data.response);
|
||||
|
||||
return data.response;
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
toast.success(t("updated"));
|
||||
|
||||
queryClient.setQueryData(["dashboardData"], (oldData: any) => {
|
||||
if (!oldData) return undefined;
|
||||
return oldData.map((e: any) => (e.id === data.id ? data : e));
|
||||
});
|
||||
|
||||
queryClient.setQueryData(["links"], (oldData: any) => {
|
||||
if (!oldData) return undefined;
|
||||
return {
|
||||
pages: [
|
||||
oldData.pages[0].map((e: any) => (e.id === data.id ? data : e)),
|
||||
...oldData.pages.slice(1),
|
||||
],
|
||||
pageParams: oldData.pageParams,
|
||||
};
|
||||
});
|
||||
|
||||
queryClient.invalidateQueries({ queryKey: ["collections"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["tags"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["publicLinks"] });
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(error.message);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const useDeleteLink = () => {
|
||||
const { t } = useTranslation();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (id: number) => {
|
||||
const load = toast.loading(t("deleting"));
|
||||
|
||||
const response = await fetch(`/api/v1/links/${id}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
|
||||
toast.dismiss(load);
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) throw new Error(data.response);
|
||||
|
||||
return data.response;
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
toast.success(t("deleted"));
|
||||
|
||||
queryClient.setQueryData(["dashboardData"], (oldData: any) => {
|
||||
if (!oldData) return undefined;
|
||||
return oldData.filter((e: any) => e.id !== data.id);
|
||||
});
|
||||
|
||||
queryClient.setQueryData(["links"], (oldData: any) => {
|
||||
if (!oldData) return undefined;
|
||||
return {
|
||||
pages: [
|
||||
oldData.pages[0].filter((e: any) => e.id !== data.id),
|
||||
...oldData.pages.slice(1),
|
||||
],
|
||||
pageParams: oldData.pageParams,
|
||||
};
|
||||
});
|
||||
|
||||
queryClient.invalidateQueries({ queryKey: ["collections"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["tags"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["publicLinks"] });
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(error.message);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const useGetLink = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (id: number) => {
|
||||
const response = await fetch(`/api/v1/links/${id}`);
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) throw new Error(data.response);
|
||||
|
||||
return data.response;
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
queryClient.setQueryData(["dashboardData"], (oldData: any) => {
|
||||
if (!oldData) return undefined;
|
||||
return oldData.map((e: any) => (e.id === data.id ? data : e));
|
||||
});
|
||||
|
||||
queryClient.setQueryData(["links"], (oldData: any) => {
|
||||
if (!oldData) return undefined;
|
||||
return {
|
||||
pages: [
|
||||
oldData.pages[0].map((e: any) => (e.id === data.id ? data : e)),
|
||||
...oldData.pages.slice(1),
|
||||
],
|
||||
pageParams: oldData.pageParams,
|
||||
};
|
||||
});
|
||||
|
||||
queryClient.invalidateQueries({ queryKey: ["publicLinks"] });
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const useBulkDeleteLinks = () => {
|
||||
const { t } = useTranslation();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (linkIds: number[]) => {
|
||||
const load = toast.loading(t("deleting"));
|
||||
|
||||
const response = await fetch("/api/v1/links", {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ linkIds }),
|
||||
});
|
||||
|
||||
toast.dismiss(load);
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) throw new Error(data.response);
|
||||
|
||||
return linkIds;
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
toast.success(t("deleted"));
|
||||
|
||||
queryClient.setQueryData(["dashboardData"], (oldData: any) => {
|
||||
if (!oldData) return undefined;
|
||||
return oldData.filter((e: any) => !data.includes(e.id));
|
||||
});
|
||||
|
||||
queryClient.setQueryData(["links"], (oldData: any) => {
|
||||
if (!oldData) return undefined;
|
||||
return {
|
||||
pages: [
|
||||
oldData.pages[0].filter((e: any) => !data.includes(e.id)),
|
||||
...oldData.pages.slice(1),
|
||||
],
|
||||
pageParams: oldData.pageParams,
|
||||
};
|
||||
});
|
||||
|
||||
queryClient.invalidateQueries({ queryKey: ["collections"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["tags"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["publicLinks"] });
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(error.message);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const useUploadFile = () => {
|
||||
const { t } = useTranslation();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({ link, file }: any) => {
|
||||
let fileType: ArchivedFormat | null = null;
|
||||
let linkType: "url" | "image" | "pdf" | null = null;
|
||||
|
||||
if (file?.type === "image/jpg" || file.type === "image/jpeg") {
|
||||
fileType = ArchivedFormat.jpeg;
|
||||
linkType = "image";
|
||||
} else if (file.type === "image/png") {
|
||||
fileType = ArchivedFormat.png;
|
||||
linkType = "image";
|
||||
} else if (file.type === "application/pdf") {
|
||||
fileType = ArchivedFormat.pdf;
|
||||
linkType = "pdf";
|
||||
} else {
|
||||
return { ok: false, data: "Invalid file type." };
|
||||
}
|
||||
|
||||
const load = toast.loading(t("creating"));
|
||||
|
||||
const response = await fetch("/api/v1/links", {
|
||||
body: JSON.stringify({
|
||||
...link,
|
||||
type: linkType,
|
||||
name: link.name ? link.name : file.name,
|
||||
}),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
method: "POST",
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) throw new Error(data.response);
|
||||
|
||||
if (response.ok) {
|
||||
const formBody = new FormData();
|
||||
file && formBody.append("file", file);
|
||||
|
||||
await fetch(
|
||||
`/api/v1/archives/${(data as any).response.id}?format=${fileType}`,
|
||||
{
|
||||
body: formBody,
|
||||
method: "POST",
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
toast.dismiss(load);
|
||||
|
||||
return data.response;
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
toast.success(t("created_success"));
|
||||
|
||||
queryClient.setQueryData(["dashboardData"], (oldData: any) => {
|
||||
if (!oldData) return undefined;
|
||||
return [data, ...oldData];
|
||||
});
|
||||
|
||||
queryClient.setQueryData(["links"], (oldData: any) => {
|
||||
if (!oldData) return undefined;
|
||||
return {
|
||||
pages: [[data, ...oldData?.pages[0]], ...oldData?.pages.slice(1)],
|
||||
pageParams: oldData?.pageParams,
|
||||
};
|
||||
});
|
||||
|
||||
queryClient.invalidateQueries({ queryKey: ["collections"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["tags"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["publicLinks"] });
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(error.message);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const useBulkEditLinks = () => {
|
||||
const { t } = useTranslation();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({
|
||||
links,
|
||||
newData,
|
||||
removePreviousTags,
|
||||
}: {
|
||||
links: LinkIncludingShortenedCollectionAndTags[];
|
||||
newData: Pick<
|
||||
LinkIncludingShortenedCollectionAndTags,
|
||||
"tags" | "collectionId"
|
||||
>;
|
||||
removePreviousTags: boolean;
|
||||
}) => {
|
||||
const load = toast.loading(t("updating"));
|
||||
|
||||
const response = await fetch("/api/v1/links", {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ links, newData, removePreviousTags }),
|
||||
});
|
||||
|
||||
toast.dismiss(load);
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) throw new Error(data.response);
|
||||
|
||||
return data.response;
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
toast.success(t("updated"));
|
||||
|
||||
queryClient.setQueryData(["dashboardData"], (oldData: any) => {
|
||||
if (!oldData) return undefined;
|
||||
return oldData.map((e: any) =>
|
||||
data.find((d: any) => d.id === e.id) ? data : e
|
||||
);
|
||||
});
|
||||
|
||||
queryClient.setQueryData(["links"], (oldData: any) => {
|
||||
if (!oldData) return undefined;
|
||||
return {
|
||||
pages: [
|
||||
oldData.pages[0].map((e: any) =>
|
||||
data.find((d: any) => d.id === e.id) ? data : e
|
||||
),
|
||||
...oldData.pages.slice(1),
|
||||
],
|
||||
pageParams: oldData.pageParams,
|
||||
};
|
||||
});
|
||||
|
||||
queryClient.invalidateQueries({ queryKey: ["collections"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["tags"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["publicLinks"] });
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error(error.message);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export {
|
||||
useLinks,
|
||||
useAddLink,
|
||||
useUpdateLink,
|
||||
useDeleteLink,
|
||||
useBulkDeleteLinks,
|
||||
useUploadFile,
|
||||
useGetLink,
|
||||
useBulkEditLinks,
|
||||
};
|
||||
@@ -0,0 +1,93 @@
|
||||
import {
|
||||
InfiniteData,
|
||||
useInfiniteQuery,
|
||||
UseInfiniteQueryResult,
|
||||
} from "@tanstack/react-query";
|
||||
import { useMemo } from "react";
|
||||
import {
|
||||
LinkIncludingShortenedCollectionAndTags,
|
||||
LinkRequestQuery,
|
||||
} from "@/types/global";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
const usePublicLinks = (params: LinkRequestQuery = {}) => {
|
||||
const router = useRouter();
|
||||
|
||||
const queryParamsObject = {
|
||||
sort: params.sort ?? Number(window.localStorage.getItem("sortBy")) ?? 0,
|
||||
collectionId: params.collectionId ?? router.query.id,
|
||||
tagId:
|
||||
params.tagId ?? router.pathname === "/tags/[id]"
|
||||
? router.query.id
|
||||
: undefined,
|
||||
pinnedOnly:
|
||||
params.pinnedOnly ?? router.pathname === "/links/pinned"
|
||||
? true
|
||||
: undefined,
|
||||
searchQueryString: params.searchQueryString,
|
||||
searchByName: params.searchByName,
|
||||
searchByUrl: params.searchByUrl,
|
||||
searchByDescription: params.searchByDescription,
|
||||
searchByTextContent: params.searchByTextContent,
|
||||
searchByTags: params.searchByTags,
|
||||
} as LinkRequestQuery;
|
||||
|
||||
const queryString = buildQueryString(queryParamsObject);
|
||||
|
||||
const { data, ...rest } = useFetchLinks(queryString);
|
||||
|
||||
const links = useMemo(() => {
|
||||
return data?.pages.reduce((acc, page) => {
|
||||
return [...acc, ...page];
|
||||
}, []);
|
||||
}, [data]);
|
||||
|
||||
return {
|
||||
links,
|
||||
data: { ...data, ...rest },
|
||||
} as {
|
||||
links: LinkIncludingShortenedCollectionAndTags[];
|
||||
data: UseInfiniteQueryResult<InfiniteData<any, unknown>, Error>;
|
||||
};
|
||||
};
|
||||
|
||||
const useFetchLinks = (params: string) => {
|
||||
return useInfiniteQuery({
|
||||
queryKey: ["links", { params }],
|
||||
queryFn: async (params) => {
|
||||
const response = await fetch(
|
||||
"/api/v1/public/collections/links?cursor=" +
|
||||
params.pageParam +
|
||||
((params.queryKey[1] as any).params
|
||||
? "&" + (params.queryKey[1] as any).params
|
||||
: "")
|
||||
);
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
return data.response;
|
||||
},
|
||||
initialPageParam: 0,
|
||||
refetchOnWindowFocus: false,
|
||||
getNextPageParam: (lastPage) => {
|
||||
if (lastPage.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
return lastPage.at(-1).id;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const buildQueryString = (params: LinkRequestQuery) => {
|
||||
return Object.keys(params)
|
||||
.filter((key) => params[key as keyof LinkRequestQuery] !== undefined)
|
||||
.map(
|
||||
(key) =>
|
||||
`${encodeURIComponent(key)}=${encodeURIComponent(
|
||||
params[key as keyof LinkRequestQuery] as string
|
||||
)}`
|
||||
)
|
||||
.join("&");
|
||||
};
|
||||
|
||||
export { usePublicLinks };
|
||||
@@ -13,7 +13,6 @@ const useTags = () => {
|
||||
const data = await response.json();
|
||||
return data.response;
|
||||
},
|
||||
initialData: [],
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ const useTokens = () => {
|
||||
const data = await response.json();
|
||||
return data.response as AccessToken[];
|
||||
},
|
||||
initialData: [],
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ const useUser = () => {
|
||||
return data.response;
|
||||
},
|
||||
enabled: !!userId,
|
||||
initialData: {},
|
||||
placeholderData: {},
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@ import { useCollections } from "./store/collections";
|
||||
import { useUser } from "./store/user";
|
||||
|
||||
export default function useCollectivePermissions(collectionIds: number[]) {
|
||||
const { data: collections } = useCollections();
|
||||
const { data: collections = [] } = useCollections();
|
||||
|
||||
const { data: user } = useUser();
|
||||
const { data: user = {} } = useUser();
|
||||
|
||||
const [permissions, setPermissions] = useState<Member | true>();
|
||||
useEffect(() => {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useUser } from "./store/user";
|
||||
export default function useInitialData() {
|
||||
const { status, data } = useSession();
|
||||
// const { setLinks } = useLinkStore();
|
||||
const { data: user } = useUser();
|
||||
const { data: user = {} } = useUser();
|
||||
const { setSettings } = useLocalSettingsStore();
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
import { LinkRequestQuery } from "@/types/global";
|
||||
import { useEffect, useState } from "react";
|
||||
import useDetectPageBottom from "./useDetectPageBottom";
|
||||
import { useRouter } from "next/router";
|
||||
import useLinkStore from "@/store/links";
|
||||
|
||||
export default function useLinks(
|
||||
{
|
||||
sort,
|
||||
collectionId,
|
||||
tagId,
|
||||
pinnedOnly,
|
||||
searchQueryString,
|
||||
searchByName,
|
||||
searchByUrl,
|
||||
searchByDescription,
|
||||
searchByTags,
|
||||
searchByTextContent,
|
||||
}: LinkRequestQuery = { sort: 0 }
|
||||
) {
|
||||
const { links, setLinks, resetLinks, selectedLinks, setSelectedLinks } =
|
||||
useLinkStore();
|
||||
const router = useRouter();
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
const { reachedBottom, setReachedBottom } = useDetectPageBottom();
|
||||
|
||||
const getLinks = async (isInitialCall: boolean, cursor?: number) => {
|
||||
const params = {
|
||||
sort,
|
||||
cursor,
|
||||
collectionId,
|
||||
tagId,
|
||||
pinnedOnly,
|
||||
searchQueryString,
|
||||
searchByName,
|
||||
searchByUrl,
|
||||
searchByDescription,
|
||||
searchByTags,
|
||||
searchByTextContent,
|
||||
};
|
||||
|
||||
const buildQueryString = (params: LinkRequestQuery) => {
|
||||
return Object.keys(params)
|
||||
.filter((key) => params[key as keyof LinkRequestQuery] !== undefined)
|
||||
.map(
|
||||
(key) =>
|
||||
`${encodeURIComponent(key)}=${encodeURIComponent(
|
||||
params[key as keyof LinkRequestQuery] as string
|
||||
)}`
|
||||
)
|
||||
.join("&");
|
||||
};
|
||||
|
||||
let queryString = buildQueryString(params);
|
||||
|
||||
let basePath;
|
||||
|
||||
if (router.pathname === "/dashboard") basePath = "/api/v1/dashboard";
|
||||
else if (router.pathname.startsWith("/public/collections/[id]")) {
|
||||
queryString = queryString + "&collectionId=" + router.query.id;
|
||||
basePath = "/api/v1/public/collections/links";
|
||||
} else basePath = "/api/v1/links";
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
const response = await fetch(`${basePath}?${queryString}`);
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
if (response.ok) setLinks(data.response, isInitialCall);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// Save the selected links before resetting the links
|
||||
// and then restore the selected links after resetting the links
|
||||
const previouslySelected = selectedLinks;
|
||||
resetLinks();
|
||||
|
||||
setSelectedLinks(previouslySelected);
|
||||
getLinks(true);
|
||||
}, [
|
||||
router,
|
||||
sort,
|
||||
searchQueryString,
|
||||
searchByName,
|
||||
searchByUrl,
|
||||
searchByDescription,
|
||||
searchByTextContent,
|
||||
searchByTags,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (reachedBottom) getLinks(false, links?.at(-1)?.id);
|
||||
|
||||
setReachedBottom(false);
|
||||
}, [reachedBottom]);
|
||||
|
||||
return { isLoading };
|
||||
}
|
||||
@@ -4,9 +4,9 @@ import { useCollections } from "./store/collections";
|
||||
import { useUser } from "./store/user";
|
||||
|
||||
export default function usePermissions(collectionId: number) {
|
||||
const { data: collections } = useCollections();
|
||||
const { data: collections = [] } = useCollections();
|
||||
|
||||
const { data: user } = useUser();
|
||||
const { data: user = {} } = useUser();
|
||||
|
||||
const [permissions, setPermissions] = useState<Member | true>();
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user