👔(frontend) integrate attachment-upload endpoint

Integrate the `documents/${docId}/attachment-upload/`
endpoint. This endpoint is used to upload attachments
to a document.
To have automatically the good content-type form-data,
the `fetchApi` function has been updated to remove the
prefill `Content-Type` header.
This commit is contained in:
Anthony LC
2024-08-29 16:32:16 +02:00
committed by Anthony LC
parent 3a3483b776
commit 3eb8f88b5c
4 changed files with 66 additions and 17 deletions

View File

@@ -1,34 +1,33 @@
import { baseApiUrl, useAuthStore } from '@/core'; import { baseApiUrl, useAuthStore } from '@/core';
/** import { getCSRFToken } from './utils';
* Retrieves the CSRF token from the document's cookies.
* interface FetchAPIInit extends RequestInit {
* @returns {string|null} The CSRF token if found in the cookies, or null if not present. withoutContentType?: boolean;
*/
function getCSRFToken() {
return document.cookie
.split(';')
.filter((cookie) => cookie.trim().startsWith('csrftoken='))
.map((cookie) => cookie.split('=')[1])
.pop();
} }
export const fetchAPI = async ( export const fetchAPI = async (
input: string, input: string,
init?: RequestInit, init?: FetchAPIInit,
apiVersion = '1.0', apiVersion = '1.0',
) => { ) => {
const apiUrl = `${baseApiUrl(apiVersion)}${input}`; const apiUrl = `${baseApiUrl(apiVersion)}${input}`;
const csrfToken = getCSRFToken(); const csrfToken = getCSRFToken();
const headers = {
'Content-Type': 'application/json',
...init?.headers,
...(csrfToken && { 'X-CSRFToken': csrfToken }),
};
if (init?.withoutContentType) {
delete headers?.['Content-Type' as keyof typeof headers];
}
const response = await fetch(apiUrl, { const response = await fetch(apiUrl, {
...init, ...init,
credentials: 'include', credentials: 'include',
headers: { headers,
...init?.headers,
'Content-Type': 'application/json',
...(csrfToken && { 'X-CSRFToken': csrfToken }),
},
}); });
if (response.status === 401) { if (response.status === 401) {

View File

@@ -16,3 +16,14 @@ export const errorCauses = async (response: Response, data?: unknown) => {
data, data,
}; };
}; };
/**
* Retrieves the CSRF token from the document's cookies.
*/
export function getCSRFToken() {
return document.cookie
.split(';')
.filter((cookie) => cookie.trim().startsWith('csrftoken='))
.map((cookie) => cookie.split('=')[1])
.pop();
}

View File

@@ -0,0 +1,36 @@
import { useMutation } from '@tanstack/react-query';
import { APIError, errorCauses, fetchAPI } from '@/api';
import { DocAttachment } from '../types';
interface CreateDocAttachment {
docId: string;
body: FormData;
}
export const createDocAttachment = async ({
docId,
body,
}: CreateDocAttachment): Promise<DocAttachment> => {
const response = await fetchAPI(`documents/${docId}/attachment-upload/`, {
method: 'POST',
body,
withoutContentType: true,
});
if (!response.ok) {
throw new APIError(
'Failed to upload on the doc',
await errorCauses(response),
);
}
return response.json() as Promise<DocAttachment>;
};
export function useCreateDocAttachment() {
return useMutation<DocAttachment, APIError, CreateDocAttachment>({
mutationFn: createDocAttachment,
});
}

View File

@@ -0,0 +1,3 @@
export interface DocAttachment {
file: string;
}