aboutsummaryrefslogtreecommitdiffstats
path: root/packages/shared
diff options
context:
space:
mode:
authorMohamed Bassem <me@mbassem.com>2024-04-19 00:09:27 +0100
committerGitHub <noreply@github.com>2024-04-19 00:09:27 +0100
commite0999f701cd1834c3d940113cd8dd5247c5fe95f (patch)
treec4169a564ecd3f933e711bcc8ef7db20532174ea /packages/shared
parentdeba31ee010f785a9739fd4df8a64a3056c9593d (diff)
downloadkarakeep-e0999f701cd1834c3d940113cd8dd5247c5fe95f.tar.zst
feature: Nested lists (#110). Fixes #62
* feature: Add support for nested lists * prevent moving the parent to a subtree
Diffstat (limited to '')
-rw-r--r--packages/shared-react/hooks/bookmarks.ts10
-rw-r--r--packages/shared-react/hooks/lists.ts78
-rw-r--r--packages/shared/utils/listUtils.ts55
3 files changed, 136 insertions, 7 deletions
diff --git a/packages/shared-react/hooks/bookmarks.ts b/packages/shared-react/hooks/bookmarks.ts
index 5f246b38..2a549d1f 100644
--- a/packages/shared-react/hooks/bookmarks.ts
+++ b/packages/shared-react/hooks/bookmarks.ts
@@ -8,7 +8,7 @@ export function useCreateBookmarkWithPostHook(
const apiUtils = api.useUtils();
const postCreationCB = useBookmarkPostCreationHook();
return api.bookmarks.createBookmark.useMutation({
- ...opts,
+ ...opts[0],
onSuccess: async (res, req, meta) => {
apiUtils.bookmarks.getBookmarks.invalidate();
apiUtils.bookmarks.searchBookmarks.invalidate();
@@ -23,7 +23,7 @@ export function useDeleteBookmark(
) {
const apiUtils = api.useUtils();
return api.bookmarks.deleteBookmark.useMutation({
- ...opts,
+ ...opts[0],
onSuccess: (res, req, meta) => {
apiUtils.bookmarks.getBookmarks.invalidate();
apiUtils.bookmarks.searchBookmarks.invalidate();
@@ -37,7 +37,7 @@ export function useUpdateBookmark(
) {
const apiUtils = api.useUtils();
return api.bookmarks.updateBookmark.useMutation({
- ...opts,
+ ...opts[0],
onSuccess: (res, req, meta) => {
apiUtils.bookmarks.getBookmarks.invalidate();
apiUtils.bookmarks.searchBookmarks.invalidate();
@@ -52,7 +52,7 @@ export function useRecrawlBookmark(
) {
const apiUtils = api.useUtils();
return api.bookmarks.recrawlBookmark.useMutation({
- ...opts,
+ ...opts[0],
onSuccess: (res, req, meta) => {
apiUtils.bookmarks.getBookmark.invalidate({ bookmarkId: req.bookmarkId });
return opts[0]?.onSuccess?.(res, req, meta);
@@ -65,7 +65,7 @@ export function useUpdateBookmarkTags(
) {
const apiUtils = api.useUtils();
return api.bookmarks.updateTags.useMutation({
- ...opts,
+ ...opts[0],
onSuccess: (res, req, meta) => {
apiUtils.bookmarks.getBookmark.invalidate({ bookmarkId: req.bookmarkId });
diff --git a/packages/shared-react/hooks/lists.ts b/packages/shared-react/hooks/lists.ts
index d5654f9f..61e50689 100644
--- a/packages/shared-react/hooks/lists.ts
+++ b/packages/shared-react/hooks/lists.ts
@@ -1,11 +1,44 @@
+import { ZBookmarkList } from "@hoarder/shared/types/lists";
+import {
+ listsToTree,
+ ZBookmarkListRoot,
+} from "@hoarder/shared/utils/listUtils";
+
import { api } from "../trpc";
+export function useCreateBookmarkList(
+ ...opts: Parameters<typeof api.lists.create.useMutation>
+) {
+ const apiUtils = api.useUtils();
+ return api.lists.create.useMutation({
+ ...opts[0],
+ onSuccess: (res, req, meta) => {
+ apiUtils.lists.list.invalidate();
+ return opts[0]?.onSuccess?.(res, req, meta);
+ },
+ });
+}
+
+export function useEditBookmarkList(
+ ...opts: Parameters<typeof api.lists.edit.useMutation>
+) {
+ const apiUtils = api.useUtils();
+ return api.lists.edit.useMutation({
+ ...opts[0],
+ onSuccess: (res, req, meta) => {
+ apiUtils.lists.list.invalidate();
+ apiUtils.lists.get.invalidate({ listId: req.listId });
+ return opts[0]?.onSuccess?.(res, req, meta);
+ },
+ });
+}
+
export function useAddBookmarkToList(
...opts: Parameters<typeof api.lists.addToList.useMutation>
) {
const apiUtils = api.useUtils();
return api.lists.addToList.useMutation({
- ...opts,
+ ...opts[0],
onSuccess: (res, req, meta) => {
apiUtils.bookmarks.getBookmarks.invalidate({ listId: req.listId });
return opts[0]?.onSuccess?.(res, req, meta);
@@ -18,10 +51,51 @@ export function useRemoveBookmarkFromList(
) {
const apiUtils = api.useUtils();
return api.lists.removeFromList.useMutation({
- ...opts,
+ ...opts[0],
onSuccess: (res, req, meta) => {
apiUtils.bookmarks.getBookmarks.invalidate({ listId: req.listId });
return opts[0]?.onSuccess?.(res, req, meta);
},
});
}
+
+export function useDeleteBookmarkList(
+ ...opts: Parameters<typeof api.lists.delete.useMutation>
+) {
+ const apiUtils = api.useUtils();
+ return api.lists.delete.useMutation({
+ ...opts[0],
+ onSuccess: (res, req, meta) => {
+ apiUtils.lists.list.invalidate();
+ apiUtils.lists.get.invalidate({ listId: req.listId });
+ return opts[0]?.onSuccess?.(res, req, meta);
+ },
+ });
+}
+
+export function useBookmarkLists(
+ ...opts: Parameters<typeof api.lists.list.useQuery>
+) {
+ return api.lists.list.useQuery(opts[0], {
+ ...opts[1],
+ select: (data) => {
+ return { data: data.lists, ...listsToTree(data.lists) };
+ },
+ });
+}
+
+export function augmentBookmarkListsWithInitialData(
+ data:
+ | {
+ data: ZBookmarkList[];
+ root: ZBookmarkListRoot;
+ allPaths: ZBookmarkList[][];
+ }
+ | undefined,
+ initialData: ZBookmarkList[],
+) {
+ if (data) {
+ return data;
+ }
+ return { data: initialData, ...listsToTree(initialData) };
+}
diff --git a/packages/shared/utils/listUtils.ts b/packages/shared/utils/listUtils.ts
new file mode 100644
index 00000000..1dd3d476
--- /dev/null
+++ b/packages/shared/utils/listUtils.ts
@@ -0,0 +1,55 @@
+import { ZBookmarkList } from "../types/lists";
+
+export interface ZBookmarkListTreeNode {
+ item: ZBookmarkList;
+ children: ZBookmarkListTreeNode[];
+}
+
+export type ZBookmarkListRoot = Record<string, ZBookmarkListTreeNode>;
+
+export function listsToTree(lists: ZBookmarkList[]) {
+ const idToList = lists.reduce<Record<string, ZBookmarkList>>((acc, list) => {
+ acc[list.id] = list;
+ return acc;
+ }, {});
+
+ const root: ZBookmarkListRoot = {};
+
+ // Prepare all refs
+ const refIdx = lists.reduce<Record<string, ZBookmarkListTreeNode>>(
+ (acc, l) => {
+ acc[l.id] = {
+ item: l,
+ children: [],
+ };
+ return acc;
+ },
+ {},
+ );
+
+ // Build the tree
+ lists.forEach((list) => {
+ const node = refIdx[list.id];
+ if (list.parentId) {
+ refIdx[list.parentId].children.push(node);
+ } else {
+ root[list.id] = node;
+ }
+ });
+
+ const allPaths: ZBookmarkList[][] = [];
+ const dfs = (node: ZBookmarkListTreeNode, path: ZBookmarkList[]) => {
+ const list = idToList[node.item.id];
+ const newPath = [...path, list];
+ allPaths.push(newPath);
+ node.children.forEach((child) => {
+ dfs(child, newPath);
+ });
+ };
+
+ Object.values(root).forEach((node) => {
+ dfs(node, []);
+ });
+
+ return { allPaths, root };
+}