mirror of
https://github.com/filecoin-project/slate.git
synced 2024-09-11 22:07:08 +03:00
feat(Upload): remove upload state from the Upload context. Instead use a store for it
This commit is contained in:
parent
f189affcbb
commit
14faf2eb2f
@ -6,11 +6,10 @@ import * as Logging from "~/common/logging";
|
||||
import * as Strings from "~/common/strings";
|
||||
import * as Styles from "~/common/styles";
|
||||
import * as Constants from "~/common/constants";
|
||||
import * as SVG from "~/common/svg";
|
||||
|
||||
import { css } from "@emotion/react";
|
||||
import { useUploadContext } from "~/components/core/Upload/Provider";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { useUploadStore } from "~/components/core/Upload/store";
|
||||
|
||||
const STYLES_LINK_INPUT = (theme) => css`
|
||||
background-color: ${theme.semantic.bgWhite};
|
||||
@ -18,21 +17,6 @@ const STYLES_LINK_INPUT = (theme) => css`
|
||||
margin-right: 8px;
|
||||
`;
|
||||
|
||||
const STYLES_JUMPER_OVERLAY = (theme) => css`
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: ${theme.zindex.jumper};
|
||||
|
||||
@supports ((-webkit-backdrop-filter: blur(75px)) or (backdrop-filter: blur(75px))) {
|
||||
-webkit-backdrop-filter: blur(75px);
|
||||
backdrop-filter: blur(75px);
|
||||
background-color: ${theme.semantic.bgBlurLightTRN};
|
||||
}
|
||||
`;
|
||||
|
||||
const STYLES_FILE_HIDDEN = css`
|
||||
height: 1px;
|
||||
width: 1px;
|
||||
@ -61,7 +45,9 @@ const STYLES_MOBILE_HIDDEN = css`
|
||||
`;
|
||||
|
||||
export function UploadJumper({ data }) {
|
||||
const [{ isUploadJumperVisible }, { upload, uploadLink, hideUploadJumper }] = useUploadContext();
|
||||
const [{ isUploadJumperVisible }, { hideUploadJumper }] = useUploadContext();
|
||||
|
||||
const { upload, uploadLink } = useUploadStore((store) => store.handlers);
|
||||
|
||||
const [state, setState] = React.useState({
|
||||
url: "",
|
||||
|
@ -5,16 +5,16 @@ import * as Constants from "~/common/constants";
|
||||
import * as SVG from "~/common/svg";
|
||||
import * as Strings from "~/common/strings";
|
||||
|
||||
import { useUploadContext } from "~/components/core/Upload/Provider";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { css } from "@emotion/react";
|
||||
import { Match, Switch } from "~/components/utility/Switch";
|
||||
import { Show } from "~/components/utility/Show";
|
||||
import { useHover } from "~/common/hooks";
|
||||
import { clamp } from "lodash";
|
||||
import { useUploadStore } from "~/components/core/Upload/store";
|
||||
|
||||
import DataMeter from "~/components/core/DataMeter";
|
||||
import BlobObjectPreview from "~/components/core/BlobObjectPreview";
|
||||
import { clamp } from "lodash";
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Popup
|
||||
* -----------------------------------------------------------------------------------------------*/
|
||||
@ -58,7 +58,11 @@ const STYLES_POPUP_CONTENT = css`
|
||||
`;
|
||||
|
||||
const useUploadPopup = ({ totalFilesSummary }) => {
|
||||
const [{ isFinished }, { resetUploadState }] = useUploadContext();
|
||||
const {
|
||||
state: { isFinished },
|
||||
handlers: { resetUploadState },
|
||||
} = useUploadStore();
|
||||
|
||||
const [popupState, setPopupState] = React.useState({
|
||||
isVisible: false,
|
||||
isSummaryExpanded: false,
|
||||
@ -159,7 +163,11 @@ const useUploadSummary = ({ fileLoading }) =>
|
||||
}, [fileLoading]);
|
||||
|
||||
export function Popup() {
|
||||
const [{ isFinished, fileLoading }, { resetUploadState }] = useUploadContext();
|
||||
const {
|
||||
state: { isFinished, fileLoading },
|
||||
handlers: { resetUploadState },
|
||||
} = useUploadStore();
|
||||
|
||||
const { uploadSummary, totalFilesSummary } = useUploadSummary({ fileLoading });
|
||||
|
||||
const [isHovered, { handleOnMouseEnter, handleOnMouseLeave }] = useHover();
|
||||
@ -244,7 +252,10 @@ const STYLES_RESET_BORDER_TOP = css`
|
||||
`;
|
||||
|
||||
function Header({ totalFilesSummary, popupState, expandUploadSummary, collapseUploadSummary }) {
|
||||
const [{ isFinished, totalBytesUploaded, totalBytes }, { retryAll }] = useUploadContext();
|
||||
const {
|
||||
state: { isFinished, totalBytesUploaded, totalBytes },
|
||||
handlers: { retryAll },
|
||||
} = useUploadStore();
|
||||
|
||||
const uploadProgress = clamp(Math.floor((totalBytesUploaded / totalBytes) * 100), 0, 100);
|
||||
|
||||
@ -353,7 +364,8 @@ const STYLES_SUMMARY_ACTION = css`
|
||||
`;
|
||||
|
||||
function Summary({ uploadSummary }) {
|
||||
const [, { retry, cancel }] = useUploadContext();
|
||||
const { retry, cancel } = useUploadStore((store) => store.handlers);
|
||||
|
||||
return (
|
||||
<div css={STYLES_SUMMARY}>
|
||||
{uploadSummary.map((file) => (
|
||||
|
@ -1,15 +1,15 @@
|
||||
import * as React from "react";
|
||||
import * as UploadUtilities from "~/common/upload-utilities";
|
||||
import * as FileUtilities from "~/common/file-utilities";
|
||||
import * as Logging from "~/common/logging";
|
||||
|
||||
import { useEventListener } from "~/common/hooks";
|
||||
import { useUploadStore } from "~/components/core/Upload/store";
|
||||
|
||||
const UploadContext = React.createContext({});
|
||||
export const useUploadContext = () => React.useContext(UploadContext);
|
||||
|
||||
export const Provider = ({ children, page, data, viewer }) => {
|
||||
const [uploadState, uploadHandlers] = useUpload({});
|
||||
const uploadHandlers = useUploadStore((store) => store.handlers);
|
||||
|
||||
const [isUploadJumperVisible, { showUploadJumper, hideUploadJumper }] = useUploadJumper();
|
||||
|
||||
@ -27,14 +27,13 @@ export const Provider = ({ children, page, data, viewer }) => {
|
||||
|
||||
const providerValue = React.useMemo(
|
||||
() => [
|
||||
{ ...uploadState, isUploadJumperVisible },
|
||||
{ isUploadJumperVisible },
|
||||
{
|
||||
...uploadHandlers,
|
||||
showUploadJumper,
|
||||
hideUploadJumper,
|
||||
},
|
||||
],
|
||||
[uploadHandlers, uploadState, isUploadJumperVisible]
|
||||
[isUploadJumperVisible]
|
||||
);
|
||||
|
||||
return <UploadContext.Provider value={providerValue}>{children}</UploadContext.Provider>;
|
||||
@ -47,159 +46,6 @@ const useUploadJumper = () => {
|
||||
return [isUploadJumperVisible, { showUploadJumper, hideUploadJumper }];
|
||||
};
|
||||
|
||||
const useUpload = () => {
|
||||
const DEFAULT_STATE = {
|
||||
fileLoading: {},
|
||||
isUploading: false,
|
||||
totalBytesUploaded: 0,
|
||||
totalBytes: 0,
|
||||
totalFilesUploaded: 0,
|
||||
totalFiles: 0,
|
||||
isFinished: false,
|
||||
};
|
||||
|
||||
const [uploadState, setUploadState] = React.useState(DEFAULT_STATE);
|
||||
|
||||
const uploadProvider = React.useMemo(() => {
|
||||
const handleStartUploading = () => {
|
||||
setUploadState((prev) => ({ ...prev, isFinished: false, isUploading: true }));
|
||||
};
|
||||
|
||||
const handleFinishUploading = () => {
|
||||
setUploadState((prev) => ({
|
||||
...DEFAULT_STATE,
|
||||
fileLoading: prev.fileLoading,
|
||||
isFinished: true,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleAddToQueue = (file) => {
|
||||
const fileKey = UploadUtilities.getFileKey(file);
|
||||
setUploadState((prev) => ({
|
||||
...prev,
|
||||
fileLoading: {
|
||||
...prev.fileLoading,
|
||||
[fileKey]: {
|
||||
id: fileKey,
|
||||
status: "saving",
|
||||
name: file.name,
|
||||
type: file.type,
|
||||
createdAt: Date.now(),
|
||||
loaded: 0,
|
||||
total: file.size,
|
||||
blob: file,
|
||||
},
|
||||
},
|
||||
isFinished: false,
|
||||
totalFiles: prev.totalFiles + 1,
|
||||
totalBytes: prev.totalBytes + file.size,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSuccess = ({ fileKey, cid }) => {
|
||||
setUploadState((prev) => {
|
||||
const newFileLoading = { ...prev.fileLoading };
|
||||
newFileLoading[fileKey].status = "saved";
|
||||
newFileLoading[fileKey].cid = cid;
|
||||
return {
|
||||
...prev,
|
||||
fileLoading: newFileLoading,
|
||||
totalFilesUploaded: prev.totalFilesUploaded + 1,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const handleDuplicate = ({ fileKey, cid }) => {
|
||||
setUploadState((prev) => {
|
||||
const newFileLoading = { ...prev.fileLoading };
|
||||
newFileLoading[fileKey].status = "duplicate";
|
||||
newFileLoading[fileKey].cid = cid;
|
||||
return {
|
||||
...prev,
|
||||
fileLoading: newFileLoading,
|
||||
totalFilesUploaded: prev.totalFilesUploaded + 1,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const handleProgress = ({ fileKey, loaded }) => {
|
||||
setUploadState((prev) => {
|
||||
const newFileLoading = { ...prev.fileLoading };
|
||||
const bytesLoaded = loaded - newFileLoading[fileKey].loaded;
|
||||
newFileLoading[fileKey].loaded = loaded;
|
||||
return {
|
||||
...prev,
|
||||
fileLoading: newFileLoading,
|
||||
totalBytesUploaded: prev.totalBytesUploaded + bytesLoaded,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const handleError = ({ fileKey }) => {
|
||||
setUploadState((prev) => {
|
||||
const newFileLoading = { ...prev.fileLoading };
|
||||
newFileLoading[fileKey].status = "failed";
|
||||
return {
|
||||
...prev,
|
||||
fileLoading: newFileLoading,
|
||||
totalFiles: prev.totalFiles - 1,
|
||||
totalBytes: prev.totalBytes - newFileLoading[fileKey].total,
|
||||
totalBytesUploaded: prev.totalBytesUploaded - newFileLoading[fileKey].total,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const handleCancelUploading = ({ fileKeys }) => {
|
||||
setUploadState((prev) => {
|
||||
const newFileLoading = { ...prev.fileLoading };
|
||||
const newTotalFiles = prev.totalFiles - fileKeys.length;
|
||||
let newTotalBytes = prev.totalBytes;
|
||||
let newTotalBytesUploaded = prev.totalBytesUploaded;
|
||||
|
||||
fileKeys.forEach((fileKey) => {
|
||||
newTotalBytes -= newFileLoading[fileKey].total;
|
||||
newTotalBytesUploaded -= newFileLoading[fileKey].loaded;
|
||||
delete newFileLoading[fileKey];
|
||||
});
|
||||
|
||||
return {
|
||||
...prev,
|
||||
fileLoading: newFileLoading,
|
||||
totalFiles: newTotalFiles,
|
||||
totalBytes: newTotalBytes,
|
||||
totalBytesUploaded: newTotalBytesUploaded,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
return UploadUtilities.createUploadProvider({
|
||||
onStart: handleStartUploading,
|
||||
onFinish: handleFinishUploading,
|
||||
onAddedToQueue: handleAddToQueue,
|
||||
onSuccess: handleSuccess,
|
||||
onDuplicate: handleDuplicate,
|
||||
onProgress: handleProgress,
|
||||
onCancel: handleCancelUploading,
|
||||
onError: handleError,
|
||||
});
|
||||
}, []);
|
||||
|
||||
const resetUploadState = () => (uploadProvider.clearUploadCache(), setUploadState(DEFAULT_STATE));
|
||||
|
||||
return [
|
||||
uploadState,
|
||||
{
|
||||
upload: uploadProvider.upload,
|
||||
uploadLink: uploadProvider.uploadLink,
|
||||
retry: uploadProvider.retry,
|
||||
retryAll: uploadProvider.retryAll,
|
||||
cancel: uploadProvider.cancel,
|
||||
cancelAll: uploadProvider.cancelAll,
|
||||
resetUploadState,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
const useUploadOnDrop = ({ upload, page, data, viewer }) => {
|
||||
const handleDragEnter = (e) => e.preventDefault();
|
||||
const handleDragLeave = (e) => e.preventDefault();
|
||||
|
177
components/core/Upload/store.js
Normal file
177
components/core/Upload/store.js
Normal file
@ -0,0 +1,177 @@
|
||||
import * as UploadUtilities from "~/common/upload-utilities";
|
||||
|
||||
import create from "zustand";
|
||||
|
||||
const DEFAULT_STATE = {
|
||||
fileLoading: {},
|
||||
isUploading: false,
|
||||
totalBytesUploaded: 0,
|
||||
totalBytes: 0,
|
||||
totalFilesUploaded: 0,
|
||||
totalFiles: 0,
|
||||
isFinished: false,
|
||||
};
|
||||
|
||||
export const useUploadStore = create((setUploadState) => {
|
||||
const handleStartUploading = () => {
|
||||
setUploadState((prev) => ({
|
||||
...prev,
|
||||
state: { ...prev.state, isFinished: false, isUploading: true },
|
||||
}));
|
||||
};
|
||||
|
||||
const handleFinishUploading = () => {
|
||||
setUploadState((prev) => ({
|
||||
...prev,
|
||||
state: {
|
||||
...DEFAULT_STATE,
|
||||
fileLoading: prev.state.fileLoading,
|
||||
isFinished: true,
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
const handleAddToQueue = (file) => {
|
||||
const fileKey = UploadUtilities.getFileKey(file);
|
||||
setUploadState((prev) => ({
|
||||
...prev,
|
||||
state: {
|
||||
...prev.state,
|
||||
fileLoading: {
|
||||
...prev.state.fileLoading,
|
||||
[fileKey]: {
|
||||
id: fileKey,
|
||||
status: "saving",
|
||||
name: file.name,
|
||||
type: file.type,
|
||||
createdAt: Date.now(),
|
||||
loaded: 0,
|
||||
total: file.size,
|
||||
blob: file,
|
||||
},
|
||||
},
|
||||
isFinished: false,
|
||||
totalFiles: prev.state.totalFiles + 1,
|
||||
totalBytes: prev.state.totalBytes + file.size,
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSuccess = ({ fileKey, cid }) => {
|
||||
setUploadState((prev) => {
|
||||
const newFileLoading = { ...prev.state.fileLoading };
|
||||
newFileLoading[fileKey].status = "saved";
|
||||
newFileLoading[fileKey].cid = cid;
|
||||
return {
|
||||
...prev,
|
||||
state: {
|
||||
...prev.state,
|
||||
fileLoading: newFileLoading,
|
||||
totalFilesUploaded: prev.state.totalFilesUploaded + 1,
|
||||
},
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const handleDuplicate = ({ fileKey, cid }) => {
|
||||
setUploadState((prev) => {
|
||||
const newFileLoading = { ...prev.state.fileLoading };
|
||||
newFileLoading[fileKey].status = "duplicate";
|
||||
newFileLoading[fileKey].cid = cid;
|
||||
return {
|
||||
...prev,
|
||||
state: {
|
||||
...prev.state,
|
||||
fileLoading: newFileLoading,
|
||||
totalFilesUploaded: prev.state.totalFilesUploaded + 1,
|
||||
},
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const handleProgress = ({ fileKey, loaded }) => {
|
||||
setUploadState((prev) => {
|
||||
const newFileLoading = { ...prev.state.fileLoading };
|
||||
const bytesLoaded = loaded - newFileLoading[fileKey].loaded;
|
||||
newFileLoading[fileKey].loaded = loaded;
|
||||
return {
|
||||
...prev,
|
||||
state: {
|
||||
...prev.state,
|
||||
fileLoading: newFileLoading,
|
||||
totalBytesUploaded: prev.state.totalBytesUploaded + bytesLoaded,
|
||||
},
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const handleError = ({ fileKey }) => {
|
||||
setUploadState((prev) => {
|
||||
const newFileLoading = { ...prev.state.fileLoading };
|
||||
newFileLoading[fileKey].status = "failed";
|
||||
return {
|
||||
...prev,
|
||||
state: {
|
||||
...prev.state,
|
||||
fileLoading: newFileLoading,
|
||||
totalFiles: prev.state.totalFiles - 1,
|
||||
totalBytes: prev.state.totalBytes - newFileLoading[fileKey].total,
|
||||
totalBytesUploaded: prev.state.totalBytesUploaded - newFileLoading[fileKey].total,
|
||||
},
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const handleCancelUploading = ({ fileKeys }) => {
|
||||
setUploadState((prev) => {
|
||||
const newFileLoading = { ...prev.state.fileLoading };
|
||||
const newTotalFiles = prev.state.totalFiles - fileKeys.length;
|
||||
let newTotalBytes = prev.state.totalBytes;
|
||||
let newTotalBytesUploaded = prev.state.totalBytesUploaded;
|
||||
|
||||
fileKeys.forEach((fileKey) => {
|
||||
newTotalBytes -= newFileLoading[fileKey].total;
|
||||
newTotalBytesUploaded -= newFileLoading[fileKey].loaded;
|
||||
delete newFileLoading[fileKey];
|
||||
});
|
||||
|
||||
return {
|
||||
...prev,
|
||||
state: {
|
||||
...prev.state,
|
||||
fileLoading: newFileLoading,
|
||||
totalFiles: newTotalFiles,
|
||||
totalBytes: newTotalBytes,
|
||||
totalBytesUploaded: newTotalBytesUploaded,
|
||||
},
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const uploadProvider = UploadUtilities.createUploadProvider({
|
||||
onStart: handleStartUploading,
|
||||
onFinish: handleFinishUploading,
|
||||
onAddedToQueue: handleAddToQueue,
|
||||
onSuccess: handleSuccess,
|
||||
onDuplicate: handleDuplicate,
|
||||
onProgress: handleProgress,
|
||||
onCancel: handleCancelUploading,
|
||||
onError: handleError,
|
||||
});
|
||||
|
||||
const resetUploadState = () => (uploadProvider.clearUploadCache(), setUploadState(DEFAULT_STATE));
|
||||
|
||||
return {
|
||||
state: DEFAULT_STATE,
|
||||
handlers: {
|
||||
upload: uploadProvider.upload,
|
||||
uploadLink: uploadProvider.uploadLink,
|
||||
saveCopy: uploadProvider.saveCopy,
|
||||
retry: uploadProvider.retry,
|
||||
retryAll: uploadProvider.retryAll,
|
||||
cancel: uploadProvider.cancel,
|
||||
cancelAll: uploadProvider.cancelAll,
|
||||
resetUploadState,
|
||||
},
|
||||
};
|
||||
});
|
@ -88,7 +88,8 @@
|
||||
"universal-cookie": "^4.0.4",
|
||||
"uuid": "^8.3.2",
|
||||
"webpack": "^5.37.1",
|
||||
"ws": "^7.4.3"
|
||||
"ws": "^7.4.3",
|
||||
"zustand": "^3.6.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.15.0",
|
||||
|
Loading…
Reference in New Issue
Block a user