UNPKG

@selfcommunity/react-ui

Version:

React UI Components to integrate a Community created with SelfCommunity Platform.

159 lines (158 loc) • 7.16 kB
import { __awaiter } from "tslib"; import { useChunkFinishListener, useChunkStartListener, useItemErrorListener, useItemFinishListener, useRequestPreSend } from '@rpldy/chunked-uploady'; import { useItemProgressListener, useItemStartListener } from '@rpldy/uploady'; import { Endpoints, http } from '@selfcommunity/api-services'; import { useSCContext, useSCUser } from '@selfcommunity/react-core'; import { Logger, resizeImage } from '@selfcommunity/utils'; import React, { useEffect, useRef, useState } from 'react'; import { useIntl } from 'react-intl'; import { SCOPE_SC_UI } from '../../constants/Errors'; import messages from '../../messages/common'; import { md5 } from '../../utils/hash'; export default (props) => { // PROPS const { type = null, onSuccess = null, onProgress = null, onError = null } = props; // REFS const firstRender = useRef(true); const chunkStateRef = React.useRef({ chunks: {}, setChunk: null, setChunks: null }); // STATE const [chunks, _setChunks] = useState({}); const setChunk = (chunk) => { const _chunks = Object.assign(Object.assign({}, chunkStateRef.current.chunks), { [chunk.id]: Object.assign(Object.assign({}, chunkStateRef.current.chunks[chunk.id]), chunk) }); _setChunks(_chunks); chunkStateRef.current.chunks = _chunks; }; const setChunks = (chunks) => { _setChunks(chunks); chunkStateRef.current.chunks = chunks; }; // Using refs to have the correct chunks values in the callbacks // https://stackoverflow.com/questions/57847594/react-hooks-accessing-up-to-date-state-from-within-a-callback chunkStateRef.current = { chunks, setChunk, setChunks }; // CONTEXT const scContext = useSCContext(); const { refreshSession } = useSCUser(); // INTL const intl = useIntl(); // component update useEffect(() => { if (firstRender.current) { firstRender.current = false; return; } onProgress && onProgress(chunks); }, [chunks]); // LISTENERS useItemStartListener((item) => { if (item.file.type.startsWith('image/')) { const reader = new FileReader(); reader.onload = (e) => { chunkStateRef.current.setChunk({ id: item.id, image: e.target.result }); }; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore reader.readAsDataURL(item.file); } chunkStateRef.current.setChunk({ id: item.id, ['upload_id']: null, completed: 0, name: item.file.name }); }); useItemProgressListener((item) => { chunkStateRef.current.setChunk({ id: item.id, completed: item.completed }); }); useItemFinishListener((item) => { md5(item.file, 2142880, (hash) => { const formData = new FormData(); formData.append('upload_id', chunkStateRef.current.chunks[item.id].upload_id); formData.append('type', chunkStateRef.current.chunks[item.id].type); formData.append('md5', hash); http .request({ url: Endpoints.ComposerChunkUploadMediaComplete.url(), method: Endpoints.ComposerChunkUploadMediaComplete.method, data: formData, headers: { 'Content-Type': 'multipart/form-data' } }) .then((res) => { setTimeout(() => { const _chunks = Object.assign({}, chunkStateRef.current.chunks); delete _chunks[item.id]; chunkStateRef.current.setChunks(_chunks); onSuccess(res.data); }, 0); }) .catch((error) => { console.log(error); onError(Object.assign({}, chunkStateRef.current.chunks[item.id]), intl.formatMessage(messages.fileUploadErrorGeneric)); const _chunks = Object.assign({}, chunkStateRef.current.chunks); delete _chunks[item.id]; chunkStateRef.current.setChunks(_chunks); }); }); }); useItemErrorListener((item) => { onError(Object.assign({}, chunkStateRef.current.chunks[item.id]), intl.formatMessage(messages.fileUploadErrorGeneric)); const _chunks = Object.assign({}, chunkStateRef.current.chunks); delete _chunks[item.id]; chunkStateRef.current.setChunks(_chunks); }); useChunkStartListener((data) => { const res = { url: `${scContext.settings.portal}${Endpoints.ComposerChunkUploadMedia.url()}`, sendOptions: { paramName: 'image', method: Endpoints.ComposerChunkUploadMedia.method, formatServerResponse: (response, status, _headers) => __awaiter(void 0, void 0, void 0, function* () { if (status === 401) { yield refreshSession(); } return Promise.resolve(JSON.parse(response)); }) } }; if (chunkStateRef.current.chunks[data.item.id].upload_id) { res.sendOptions.params = { ['upload_id']: chunkStateRef.current.chunks[data.item.id].upload_id }; } else { chunkStateRef.current.setChunk({ id: data.item.id, type: type || data.sendOptions.paramName }); } return res; }); useChunkFinishListener((data) => __awaiter(void 0, void 0, void 0, function* () { const _data = yield data.uploadData.response.data; chunkStateRef.current.setChunk({ id: data.item.id, ['upload_id']: _data.upload_id }); })); useRequestPreSend(({ items, options }) => __awaiter(void 0, void 0, void 0, function* () { const destination = ['JWT', 'OAuth'].includes(scContext.settings.session.type) ? { headers: { Authorization: `Bearer ${scContext.settings.session.authToken.accessToken}` } } : {}; if (items.length == 0) { return Promise.resolve({ options, destination }); } //returned object can be wrapped with a promise return new Promise((resolve) => { Promise.all(items.map((item) => __awaiter(void 0, void 0, void 0, function* () { return Object.assign(Object.assign({}, item), { file: item.file.type.startsWith('image/') && item.file.type !== 'image/gif' ? yield resizeImage(item.file) : item.file }); }))) .then((items) => { resolve({ items: items, options: { inputFieldName: options.inputFieldName, destination } }); }) .catch((error) => { Logger.error(error, SCOPE_SC_UI); resolve({ options: { inputFieldName: options.inputFieldName, destination } }); }); }); })); return null; };