Skip to content

Commit

Permalink
DOKY-146 Upload a new file to document (#109)
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
hanna-eismant authored Sep 3, 2024
1 parent 69cb8c1 commit c9d8ffe
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 19 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,4 @@ server/out
/server/src/main/resources/static/
/server/property 'buildDir'/
/filestorage/
**/.DS_Store
2 changes: 1 addition & 1 deletion server/doky-front/src/api/config.local.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const BASE_URL = 'http://localhost:8119';
export const BASE_URL = 'http://localhost:8080';
4 changes: 3 additions & 1 deletion server/doky-front/src/api/documents.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {get, post, put} from './request';
import {get, post, postFormData, put} from './request';

const RESOURCE_NAME = 'documents';

Expand All @@ -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);
30 changes: 19 additions & 11 deletions server/doky-front/src/api/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
});
Expand All @@ -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);

Expand Down
36 changes: 36 additions & 0 deletions server/doky-front/src/components/formComponents/FileUploader.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<>
<div className="mt-4">
<label htmlFor={inputId} className="form-label">Select file to upload:</label>
<input className="form-control" type="file" id={inputId} onChange={handleFileChange}/>
</div>
{file &&
<button type="button" className="btn btn-outline-primary me-2 mt-2" onClick={handleUpload}>
<i className="bi bi-cloud-upload me-1"></i><span>Upload</span>
</button>
}
</>
);
};

export default FileUploader;
Original file line number Diff line number Diff line change
@@ -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);
Expand All @@ -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 (
<div className="container-fluid">
<div className="row">
Expand All @@ -29,12 +45,10 @@ const EditDocumentForm = ({document}) => {
<div>File:</div>
<div>{document.fileName}</div>
<div>
<button type="button" className="btn btn-outline-primary me-2">
<i className="bi bi-cloud-upload me-1"></i><span>Upload New</span>
</button>
<button type="button" className="btn btn-outline-primary me-2" disabled={!document.fileName}>
<i className="bi bi-cloud-download me-1"></i><span>Download</span>
</button>
<FileUploader onUpload={onUpload}/>
</div>
</div>
<div className="d-flex justify-content-between py-2 mt-5 border-top">
Expand Down
1 change: 1 addition & 0 deletions server/src/main/resources/application-local.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit c9d8ffe

Please sign in to comment.