👔(frontend) create versions api endpoints

Create versions api endpoints:
- Add useDocVersion hook - to retrieve a version
- Add useDocVersions hook - to list versions with
pagination

We add an helper to type more easily the react-query
hooks.
This commit is contained in:
Anthony LC
2024-07-17 09:27:20 +02:00
committed by Anthony LC
parent 91be4f5a21
commit 424c100eeb
8 changed files with 180 additions and 2 deletions

View File

@@ -0,0 +1,46 @@
import {
DefinedInitialDataInfiniteOptions,
InfiniteData,
QueryKey,
UseQueryOptions,
useInfiniteQuery,
} from '@tanstack/react-query';
import { APIError } from './APIError';
import { APIList } from './types';
export type UseQueryOptionsAPI<Q> = UseQueryOptions<Q, APIError, Q>;
export type DefinedInitialDataInfiniteOptionsAPI<Q> =
DefinedInitialDataInfiniteOptions<
Q,
APIError,
InfiniteData<Q>,
QueryKey,
number
>;
/**
* @param param Used for infinite scroll pagination
* @param queryConfig
* @returns
*/
export const useAPIInfiniteQuery = <T, Q extends { next?: APIList<Q>['next'] }>(
key: string,
api: (props: T & { page: number }) => Promise<Q>,
param: T,
queryConfig?: DefinedInitialDataInfiniteOptionsAPI<Q>,
) => {
return useInfiniteQuery<Q, APIError, InfiniteData<Q>, QueryKey, number>({
initialPageParam: 1,
queryKey: [key, param],
queryFn: ({ pageParam }) =>
api({
...param,
page: pageParam,
}),
getNextPageParam(lastPage, allPages) {
return lastPage.next ? allPages.length + 1 : undefined;
},
...queryConfig,
});
};

View File

@@ -1,4 +1,5 @@
export * from './APIError';
export * from './fetchApi';
export * from './helpers';
export * from './types';
export * from './utils';

View File

@@ -4,7 +4,8 @@ import { useCallback, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import * as Y from 'yjs';
import { useUpdateDoc } from '@/features/docs/doc-management/';
import { KEY_DOC, useUpdateDoc } from '@/features/docs/doc-management/';
import { KEY_LIST_DOC_VERSIONS } from '@/features/docs/doc-versioning';
import { toBase64 } from '../utils';
@@ -21,6 +22,7 @@ const useSaveDoc = (docId: string, doc: Y.Doc, canSave: boolean) => {
VariantType.SUCCESS,
);
},
listInvalideQueries: [KEY_LIST_DOC_VERSIONS, KEY_DOC],
});
const [initialDoc, setInitialDoc] = useState<string>(
toBase64(Y.encodeStateAsUpdate(doc)),

View File

@@ -0,0 +1 @@
export * from './useDocVersions';

View File

@@ -0,0 +1,41 @@
import { useQuery } from '@tanstack/react-query';
import { APIError, UseQueryOptionsAPI, errorCauses, fetchAPI } from '@/api';
import { Version } from '../types';
export type DocVersionParam = {
docId: string;
versionId: string;
};
const getDocVersion = async ({
versionId,
docId,
}: DocVersionParam): Promise<Version> => {
const url = `documents/${docId}/versions/${versionId}/`;
const response = await fetchAPI(url);
if (!response.ok) {
throw new APIError(
'Failed to get the doc version',
await errorCauses(response),
);
}
return response.json() as Promise<Version>;
};
export const KEY_DOC_VERSION = 'doc-version';
export function useDocVersion(
params: DocVersionParam,
queryConfig?: UseQueryOptionsAPI<Version>,
) {
return useQuery<Version, APIError, Version>({
queryKey: [KEY_DOC_VERSION, params],
queryFn: () => getDocVersion(params),
...queryConfig,
});
}

View File

@@ -0,0 +1,66 @@
import { useQuery } from '@tanstack/react-query';
import {
APIError,
APIList,
DefinedInitialDataInfiniteOptionsAPI,
UseQueryOptionsAPI,
errorCauses,
fetchAPI,
useAPIInfiniteQuery,
} from '@/api';
import { Versions } from '../types';
export type DocVersionsParam = {
docId: string;
};
export type DocVersionsAPIParams = DocVersionsParam & {
page: number;
};
type VersionsResponse = APIList<Versions>;
const getDocVersions = async ({
page,
docId,
}: DocVersionsAPIParams): Promise<VersionsResponse> => {
const url = `documents/${docId}/versions/?page=${page}`;
const response = await fetchAPI(url);
if (!response.ok) {
throw new APIError(
'Failed to get the doc versions',
await errorCauses(response),
);
}
return response.json() as Promise<VersionsResponse>;
};
export const KEY_LIST_DOC_VERSIONS = 'doc-versions';
export function useDocVersions(
params: DocVersionsAPIParams,
queryConfig?: UseQueryOptionsAPI<VersionsResponse>,
) {
return useQuery<VersionsResponse, APIError, VersionsResponse>({
queryKey: [KEY_LIST_DOC_VERSIONS, params],
queryFn: () => getDocVersions(params),
...queryConfig,
});
}
export function useDocVersionsInfiniteQuery(
param: DocVersionsParam,
queryConfig?: DefinedInitialDataInfiniteOptionsAPI<VersionsResponse>,
) {
return useAPIInfiniteQuery<DocVersionsParam, VersionsResponse>(
KEY_LIST_DOC_VERSIONS,
getDocVersions,
param,
queryConfig,
);
}

View File

@@ -0,0 +1,13 @@
import { Doc } from '../doc-management';
export interface Versions {
etag: string;
is_latest: boolean;
last_modified: string;
version_id: string;
}
export interface Version {
content: Doc['content'];
last_modified: string;
}

View File

@@ -5,7 +5,12 @@ import {
} from '@tanstack/react-query';
import { APIError, errorCauses, fetchAPI } from '@/api';
import { Access, KEY_DOC, Role } from '@/features/docs/doc-management';
import {
Access,
KEY_DOC,
KEY_LIST_DOC,
Role,
} from '@/features/docs/doc-management';
import { KEY_LIST_DOC_ACCESSES } from './useDocAccesses';
@@ -54,6 +59,9 @@ export const useUpdateDocAccess = (options?: UseUpdateDocAccessOptions) => {
void queryClient.invalidateQueries({
queryKey: [KEY_DOC],
});
void queryClient.invalidateQueries({
queryKey: [KEY_LIST_DOC],
});
if (options?.onSuccess) {
options.onSuccess(data, variables, context);
}