/ src / hooks / useBlockLinks.ts
useBlockLinks.ts
  1  import useSWR from 'swr';
  2  import {
  3      getLinksFromApiV1LinksFromBlockIdGet,
  4      getLinksToApiV1LinksToBlockIdGet
  5  } from '@/data/v1-links';
  6  import { fetchLinks } from '@/utils/links';
  7  import type { GetLinksFromApiV1LinksFromBlockIdGetParams } from '@/data/models/getLinksFromApiV1LinksFromBlockIdGetParams';
  8  import type { GetLinksToApiV1LinksToBlockIdGetParams } from '@/data/models/getLinksToApiV1LinksToBlockIdGetParams';
  9  import type { BlockLink } from '@/data/models/blockLink';
 10  import type { PaginatedLinksResponse } from '@/data/models/paginatedLinksResponse';
 11  
 12  /**
 13   * Hook for fetching all block links with pagination support
 14   * @param branch - Optional branch name to fetch links from (defaults to 'main')
 15   * @param namespace - Optional namespace to filter links (defaults to 'legacy')
 16   * @param cursor - Optional cursor for pagination
 17   * @param limit - Optional limit for number of results
 18   */
 19  export function useLinks(
 20      branch?: string,
 21      namespace?: string,
 22      cursor?: string,
 23      limit?: number
 24  ) {
 25      const key = [
 26          'links',
 27          ...(branch ? [branch] : []),
 28          ...(namespace ? [namespace] : []),
 29          ...(cursor ? [cursor] : []),
 30          ...(limit ? [limit.toString()] : [])
 31      ];
 32      const { data, error, isLoading, mutate } = useSWR(key, () =>
 33          fetchLinks(branch, namespace, cursor, limit)
 34      );
 35  
 36      return {
 37          links: data?.links as BlockLink[] | undefined,
 38          nextCursor: data?.next_cursor,
 39          pageSize: data?.page_size,
 40          totalAvailable: data?.total_available,
 41          isLoading,
 42          isError: error,
 43          mutate
 44      };
 45  }
 46  
 47  /**
 48   * Hook for fetching links from a specific block (outbound links)
 49   */
 50  export function useLinksFrom(
 51      blockId: string,
 52      params?: GetLinksFromApiV1LinksFromBlockIdGetParams
 53  ) {
 54      const { data, error, isLoading, mutate } = useSWR(
 55          blockId ? ['links-from', blockId, params] : null,
 56          async () => {
 57              const response = await getLinksFromApiV1LinksFromBlockIdGet(blockId, params);
 58              if (response.status === 200) {
 59                  return response.data as PaginatedLinksResponse;
 60              }
 61              throw new Error(`Failed to fetch links: ${response.status}`);
 62          }
 63      );
 64  
 65      return {
 66          links: data?.links as BlockLink[] | undefined,
 67          nextCursor: data?.next_cursor,
 68          pageSize: data?.page_size,
 69          totalAvailable: data?.total_available,
 70          isLoading,
 71          isError: error,
 72          mutate
 73      };
 74  }
 75  
 76  /**
 77   * Hook for fetching links to a specific block (inbound links)
 78   */
 79  export function useLinksTo(
 80      blockId: string,
 81      params?: GetLinksToApiV1LinksToBlockIdGetParams
 82  ) {
 83      const { data, error, isLoading, mutate } = useSWR(
 84          blockId ? ['links-to', blockId, params] : null,
 85          async () => {
 86              const response = await getLinksToApiV1LinksToBlockIdGet(blockId, params);
 87              if (response.status === 200) {
 88                  return response.data as PaginatedLinksResponse;
 89              }
 90              throw new Error(`Failed to fetch links: ${response.status}`);
 91          }
 92      );
 93  
 94      return {
 95          links: data?.links as BlockLink[] | undefined,
 96          nextCursor: data?.next_cursor,
 97          pageSize: data?.page_size,
 98          totalAvailable: data?.total_available,
 99          isLoading,
100          isError: error,
101          mutate
102      };
103  }
104  
105  /**
106   * Hook for fetching both inbound and outbound links for a block
107   */
108  export function useBlockLinks(
109      blockId: string,
110      params?: {
111          from?: GetLinksFromApiV1LinksFromBlockIdGetParams;
112          to?: GetLinksToApiV1LinksToBlockIdGetParams;
113      }
114  ) {
115      const linksFrom = useLinksFrom(blockId, params?.from);
116      const linksTo = useLinksTo(blockId, params?.to);
117  
118      return {
119          linksFrom: linksFrom.links,
120          linksTo: linksTo.links,
121          fromPagination: {
122              nextCursor: linksFrom.nextCursor,
123              pageSize: linksFrom.pageSize,
124              totalAvailable: linksFrom.totalAvailable
125          },
126          toPagination: {
127              nextCursor: linksTo.nextCursor,
128              pageSize: linksTo.pageSize,
129              totalAvailable: linksTo.totalAvailable
130          },
131          isLoading: linksFrom.isLoading || linksTo.isLoading,
132          isError: linksFrom.isError || linksTo.isError,
133          mutate: () => {
134              linksFrom.mutate();
135              linksTo.mutate();
136          }
137      };
138  }