From c9d8ffe978291e3c259b79927e521a31702d021c Mon Sep 17 00:00:00 2001 From: Hanna Kurhuzenkava Date: Tue, 3 Sep 2024 21:15:53 +0300 Subject: [PATCH] DOKY-146 Upload a new file to document (#109) * DOKY-146 Upload a new file to document Improve API request header generation Enhancements in the process of generating headers in API requests occurred, with functionalities now split into two separate functions: one that manages authorization headers, and another which handles content-type headers. Increased code clarity and maintainability are expected benefits. Update local development base URL and refine API request methods The base URL for local development has been changed from port 8119 to 8080. Improvements have been made to the API request methods to handle different content-type more efficiently. The `prepareBody` function was removed, and data is now directly stringified, streamlining the code and offering increased flexibility in managing various content-types. Incorporate `documentId` within `SingleFileUploader` Updates were made to the `SingleFileUploader` component, namely with the addition of a `documentId` parameter. This change enhances the file uploading feature in the application, as tracking of the uploaded document is now possible. The form using this component has also been adjusted to provide the `documentId`. * Fix formatting issues and clean up unused console logs Corrected inconsistent quotation marks and improved indentation in various files. Removed unused console logs and added TODO comments to enhance future development. * Add file upload support in `EditDocumentForm` Refactor `SingleFileUploader` to `FileUploader` with upload functionality. Integrated new upload handler in `EditDocumentForm` to handle document uploads, including toast notifications upon success or failure. Simplified async call in `postFormData` to return fetch promise. * Remove `documentId` prop from `FileUploader` The `documentId` prop in the `FileUploader` component was redundant and has been removed. --- .gitignore | 1 + server/doky-front/src/api/config.local.js | 2 +- server/doky-front/src/api/documents.js | 4 ++- server/doky-front/src/api/request.js | 30 ++++++++++------ .../formComponents/FileUploader.jsx | 36 +++++++++++++++++++ .../EditDocumentForm/EditDocumentForm.jsx | 26 ++++++++++---- .../resources/application-local.properties | 1 + 7 files changed, 81 insertions(+), 19 deletions(-) create mode 100644 server/doky-front/src/components/formComponents/FileUploader.jsx diff --git a/.gitignore b/.gitignore index 0b8874a5..b1aa81f5 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,4 @@ server/out /server/src/main/resources/static/ /server/property 'buildDir'/ /filestorage/ +**/.DS_Store diff --git a/server/doky-front/src/api/config.local.js b/server/doky-front/src/api/config.local.js index 06b817b2..4bcb1dcb 100644 --- a/server/doky-front/src/api/config.local.js +++ b/server/doky-front/src/api/config.local.js @@ -1 +1 @@ -export const BASE_URL = 'http://localhost:8119'; +export const BASE_URL = 'http://localhost:8080'; diff --git a/server/doky-front/src/api/documents.js b/server/doky-front/src/api/documents.js index 51c9f5fd..2f108945 100644 --- a/server/doky-front/src/api/documents.js +++ b/server/doky-front/src/api/documents.js @@ -1,4 +1,4 @@ -import {get, post, put} from './request'; +import {get, post, postFormData, put} from './request'; const RESOURCE_NAME = 'documents'; @@ -9,3 +9,5 @@ export const getDocument = id => get(`${RESOURCE_NAME}/${id}`); export const createDocument = payload => post(RESOURCE_NAME, payload); export const updateDocument = payload => put(`${RESOURCE_NAME}/${payload.id}`, payload); + +export const uploadDocument = (documentId, formData) => postFormData(`${RESOURCE_NAME}/${documentId}/upload`, formData); diff --git a/server/doky-front/src/api/request.js b/server/doky-front/src/api/request.js index 4653b726..c25182e4 100644 --- a/server/doky-front/src/api/request.js +++ b/server/doky-front/src/api/request.js @@ -2,25 +2,25 @@ import {BASE_URL} from 'config'; const apiPrefix = '/api'; -const HEADERS = { - 'Content-Type': 'application/json' +const getAuthHeader = () => { + const jwt = localStorage.getItem('jwt'); + return jwt ? {Authorization: `Bearer ${jwt}`} : {}; }; -const getHeaders = () => { - const jwt = localStorage.getItem('jwt'); - return jwt ? { - Authorization: `Bearer ${jwt}`, - ...HEADERS - } : HEADERS; +const getContentTypeHeader = (contentType) => { + return contentType ? {'Content-Type': contentType} : {}; }; -const getDefaultOptions = () => ({ - headers: getHeaders() +const getDefaultOptions = (contentType) => ({ + headers: { + ...getAuthHeader(), + ...getContentTypeHeader(contentType) + } }); const request = async (url, method, data = {}) => { const response = await fetch(BASE_URL + apiPrefix + '/' + url, { - ...getDefaultOptions(), + ...getDefaultOptions('application/json'), method, body: JSON.stringify(data) }); @@ -35,6 +35,14 @@ const request = async (url, method, data = {}) => { export const post = (url, data = {}) => request(url, 'POST', data); +export const postFormData = (url, formData = {}) => { + return fetch(BASE_URL + apiPrefix + '/' + url, { + ...getDefaultOptions(), + method: 'POST', + body: formData + }); +}; + export const put = async (url, data = {}) => request(url, 'PUT', data); diff --git a/server/doky-front/src/components/formComponents/FileUploader.jsx b/server/doky-front/src/components/formComponents/FileUploader.jsx new file mode 100644 index 00000000..b7a54588 --- /dev/null +++ b/server/doky-front/src/components/formComponents/FileUploader.jsx @@ -0,0 +1,36 @@ +import React, {useId, useState} from 'react'; + +const FileUploader = ({onUpload}) => { + + const [file, setFile] = useState(null); + const id = useId(); + const inputId = `file-input-${id}`; + + const handleFileChange = (e) => { + if (e.target.files && e.target.files[0]) { + setFile(e.target.files[0]); + } + }; + + const handleUpload = () => { + const formData = new FormData(); + formData.append('file', file); + onUpload(formData); + }; + + return ( + <> +
+ + +
+ {file && + + } + + ); +}; + +export default FileUploader; diff --git a/server/doky-front/src/pages/Documents/EditDocumentForm/EditDocumentForm.jsx b/server/doky-front/src/pages/Documents/EditDocumentForm/EditDocumentForm.jsx index 5e04f1fe..51ddfeb4 100644 --- a/server/doky-front/src/pages/Documents/EditDocumentForm/EditDocumentForm.jsx +++ b/server/doky-front/src/pages/Documents/EditDocumentForm/EditDocumentForm.jsx @@ -1,11 +1,12 @@ import React from 'react'; -import HorizontalFormInput from '../../../components/formComponents/HorizontalFormInput.jsx'; -import HorizontalFormText from '../../../components/formComponents/HorizontalFormText.jsx'; import {useAddToast} from '../../../components/Toasts'; import {useMutation} from '../../../hooks/useMutation.js'; -import {updateDocument} from '../../../api/documents.js'; +import {updateDocument, uploadDocument} from '../../../api/documents.js'; import {useForm} from '../../../hooks/useForm.js'; import AlertError from '../../../components/AlertError.jsx'; +import HorizontalFormInput from '../../../components/formComponents/HorizontalFormInput.jsx'; +import HorizontalFormText from '../../../components/formComponents/HorizontalFormText.jsx'; +import FileUploader from '../../../components/formComponents/FileUploader.jsx'; const EditDocumentForm = ({document}) => { const [editDocument, {isLoading}] = useMutation(updateDocument); @@ -15,6 +16,21 @@ const EditDocumentForm = ({document}) => { addToast('saved'); }); + const onUpload = async (formData) => { + + try { + const response = await uploadDocument(document.id, formData); + if (response.ok) { + addToast('uploaded'); + } else { + console.error(response); + } + } catch (error) { + console.error(error); + } + + }; + return (
@@ -29,12 +45,10 @@ const EditDocumentForm = ({document}) => {
File:
{document.fileName}
- +
diff --git a/server/src/main/resources/application-local.properties b/server/src/main/resources/application-local.properties index 976ecded..86590cc3 100644 --- a/server/src/main/resources/application-local.properties +++ b/server/src/main/resources/application-local.properties @@ -13,6 +13,7 @@ spring.mail.username="" spring.mail.password="" # spa resources routing doky.static.caching=false +spring.web.resources.cache.period=0s logging.level.web=DEBUG