From 424c100eebc3ef166abd809a16aeb31d65f8d54f Mon Sep 17 00:00:00 2001 From: Anthony LC Date: Wed, 17 Jul 2024 09:27:20 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=91=94(frontend)=20create=20versions=20ap?= =?UTF-8?q?i=20endpoints?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- src/frontend/apps/impress/src/api/helpers.tsx | 46 +++++++++++++ src/frontend/apps/impress/src/api/index.ts | 1 + .../docs/doc-editor/hook/useSaveDoc.tsx | 4 +- .../features/docs/doc-versioning/api/index.ts | 1 + .../docs/doc-versioning/api/useDocVersion.tsx | 41 ++++++++++++ .../doc-versioning/api/useDocVersions.tsx | 66 +++++++++++++++++++ .../src/features/docs/doc-versioning/types.ts | 13 ++++ .../members-list/api/useUpdateDocAccess.ts | 10 ++- 8 files changed, 180 insertions(+), 2 deletions(-) create mode 100644 src/frontend/apps/impress/src/api/helpers.tsx create mode 100644 src/frontend/apps/impress/src/features/docs/doc-versioning/api/index.ts create mode 100644 src/frontend/apps/impress/src/features/docs/doc-versioning/api/useDocVersion.tsx create mode 100644 src/frontend/apps/impress/src/features/docs/doc-versioning/api/useDocVersions.tsx create mode 100644 src/frontend/apps/impress/src/features/docs/doc-versioning/types.ts diff --git a/src/frontend/apps/impress/src/api/helpers.tsx b/src/frontend/apps/impress/src/api/helpers.tsx new file mode 100644 index 00000000..5d09463c --- /dev/null +++ b/src/frontend/apps/impress/src/api/helpers.tsx @@ -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 = UseQueryOptions; +export type DefinedInitialDataInfiniteOptionsAPI = + DefinedInitialDataInfiniteOptions< + Q, + APIError, + InfiniteData, + QueryKey, + number + >; + +/** + * @param param Used for infinite scroll pagination + * @param queryConfig + * @returns + */ +export const useAPIInfiniteQuery = ['next'] }>( + key: string, + api: (props: T & { page: number }) => Promise, + param: T, + queryConfig?: DefinedInitialDataInfiniteOptionsAPI, +) => { + return useInfiniteQuery, QueryKey, number>({ + initialPageParam: 1, + queryKey: [key, param], + queryFn: ({ pageParam }) => + api({ + ...param, + page: pageParam, + }), + getNextPageParam(lastPage, allPages) { + return lastPage.next ? allPages.length + 1 : undefined; + }, + ...queryConfig, + }); +}; diff --git a/src/frontend/apps/impress/src/api/index.ts b/src/frontend/apps/impress/src/api/index.ts index c8c14e47..33156665 100644 --- a/src/frontend/apps/impress/src/api/index.ts +++ b/src/frontend/apps/impress/src/api/index.ts @@ -1,4 +1,5 @@ export * from './APIError'; export * from './fetchApi'; +export * from './helpers'; export * from './types'; export * from './utils'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useSaveDoc.tsx b/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useSaveDoc.tsx index 319133b6..9c2ce63e 100644 --- a/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useSaveDoc.tsx +++ b/src/frontend/apps/impress/src/features/docs/doc-editor/hook/useSaveDoc.tsx @@ -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( toBase64(Y.encodeStateAsUpdate(doc)), diff --git a/src/frontend/apps/impress/src/features/docs/doc-versioning/api/index.ts b/src/frontend/apps/impress/src/features/docs/doc-versioning/api/index.ts new file mode 100644 index 00000000..fad889b3 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-versioning/api/index.ts @@ -0,0 +1 @@ +export * from './useDocVersions'; diff --git a/src/frontend/apps/impress/src/features/docs/doc-versioning/api/useDocVersion.tsx b/src/frontend/apps/impress/src/features/docs/doc-versioning/api/useDocVersion.tsx new file mode 100644 index 00000000..3af15aad --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-versioning/api/useDocVersion.tsx @@ -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 => { + 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; +}; + +export const KEY_DOC_VERSION = 'doc-version'; + +export function useDocVersion( + params: DocVersionParam, + queryConfig?: UseQueryOptionsAPI, +) { + return useQuery({ + queryKey: [KEY_DOC_VERSION, params], + queryFn: () => getDocVersion(params), + ...queryConfig, + }); +} diff --git a/src/frontend/apps/impress/src/features/docs/doc-versioning/api/useDocVersions.tsx b/src/frontend/apps/impress/src/features/docs/doc-versioning/api/useDocVersions.tsx new file mode 100644 index 00000000..fb15f944 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-versioning/api/useDocVersions.tsx @@ -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; + +const getDocVersions = async ({ + page, + docId, +}: DocVersionsAPIParams): Promise => { + 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; +}; + +export const KEY_LIST_DOC_VERSIONS = 'doc-versions'; + +export function useDocVersions( + params: DocVersionsAPIParams, + queryConfig?: UseQueryOptionsAPI, +) { + return useQuery({ + queryKey: [KEY_LIST_DOC_VERSIONS, params], + queryFn: () => getDocVersions(params), + ...queryConfig, + }); +} + +export function useDocVersionsInfiniteQuery( + param: DocVersionsParam, + queryConfig?: DefinedInitialDataInfiniteOptionsAPI, +) { + return useAPIInfiniteQuery( + KEY_LIST_DOC_VERSIONS, + getDocVersions, + param, + queryConfig, + ); +} diff --git a/src/frontend/apps/impress/src/features/docs/doc-versioning/types.ts b/src/frontend/apps/impress/src/features/docs/doc-versioning/types.ts new file mode 100644 index 00000000..4c60b988 --- /dev/null +++ b/src/frontend/apps/impress/src/features/docs/doc-versioning/types.ts @@ -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; +} diff --git a/src/frontend/apps/impress/src/features/docs/members/members-list/api/useUpdateDocAccess.ts b/src/frontend/apps/impress/src/features/docs/members/members-list/api/useUpdateDocAccess.ts index 16a7768f..b7192adf 100644 --- a/src/frontend/apps/impress/src/features/docs/members/members-list/api/useUpdateDocAccess.ts +++ b/src/frontend/apps/impress/src/features/docs/members/members-list/api/useUpdateDocAccess.ts @@ -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); }