From 0c778366196aa6f6f8e4d7eeae9bedd102df49c2 Mon Sep 17 00:00:00 2001 From: roggc Date: Sun, 2 Jan 2022 10:46:27 +0100 Subject: [PATCH 01/20] refactor --- .../FileUpload/FileUpload.stories.tsx | 61 +-- src/Containers/FileUpload/FileUpload.tsx | 478 +++++------------- .../FileUpload/IsFailureIsSuccessPanel.tsx | 7 +- src/Containers/FileUpload/StyledComponents.ts | 10 +- src/Containers/FileUpload/reducer.ts | 251 +++++++++ src/Inputs/Button/Button.tsx | 8 +- 6 files changed, 433 insertions(+), 382 deletions(-) create mode 100644 src/Containers/FileUpload/reducer.ts diff --git a/src/Containers/FileUpload/FileUpload.stories.tsx b/src/Containers/FileUpload/FileUpload.stories.tsx index 0c7a37ef8..5f0cc2cad 100644 --- a/src/Containers/FileUpload/FileUpload.stories.tsx +++ b/src/Containers/FileUpload/FileUpload.stories.tsx @@ -1,46 +1,47 @@ -import React, { useState } from 'react'; +import React from 'react'; import { Meta, Story } from '@storybook/react'; import { FileUpload, IFileUploadProps } from '../../index'; - export default { title: 'Components/FileUpload', component: FileUpload, args: { - subTitle: 'Supports: JPG, JPEG2000, PNG', - title: 'Drop your image here, or click to browse', - minHeight: 100, - setBase64: (base64StringFile: string) => { + doWithBase64StringFile: (base64StringFile: string) => { console.log(base64StringFile); }, - successMessage: 'Completed', - failureMessage: 'Something went wrong', - disabled: false, }, } as Meta; -const useStateProps = () => { - const [isUploading, setIsUploading] = useState(false); - const [isSuccess, setIsSuccess] = useState(false); - const [isFailure, setIsFailure] = useState(false); - return { - isFailure, - isSuccess, - isUploading, - setIsFailure, - setIsSuccess, - setIsUploading, - }; -}; - export const Basic: Story = (args) => ( - + ); -export const VeryLongMessageDuration: Story = (args) => ( - -); +export const LongMessageDuration = Basic.bind({}); +LongMessageDuration.args = { + ...Basic.args, + messageDuration: 10000, +}; -export const VeryShortMessageDuration: Story = (args) => ( - -); +export const BigMinHeight = Basic.bind({}); +BigMinHeight.args = { + ...Basic.args, + minHeight: 350, +}; + +export const BigMinWidth = Basic.bind({}); +BigMinWidth.args = { + ...Basic.args, + minWidth: 600, +}; + +export const TestIsFailureTrue = Basic.bind({}); +TestIsFailureTrue.args = { + ...Basic.args, + isTestIsFailure: true, +}; + +export const LongAnimationDuration = Basic.bind({}); +LongAnimationDuration.args = { + ...Basic.args, + animationDuration: 5000, +}; diff --git a/src/Containers/FileUpload/FileUpload.tsx b/src/Containers/FileUpload/FileUpload.tsx index ff82a065e..17949a9b4 100644 --- a/src/Containers/FileUpload/FileUpload.tsx +++ b/src/Containers/FileUpload/FileUpload.tsx @@ -23,299 +23,81 @@ import { Container, Icon } from './StyledComponents'; import { FileMovingAnimation } from './FileMovingAnimation'; import { IsFailureIsSuccessPanel } from './IsFailureIsSuccessPanel'; import { NO_BASE64STRINGFILE } from './constants'; - -interface IOptions { - position: boolean; - opacity: number; -} - -interface IState { - height: number | undefined; - totalHeight: number; - totalHeightPlus: number; - maxHeight: number | undefined; - loading: IOptions; - isSuccess: IOptions; - isFailure: IOptions; - positionTopLoading: number; - loadingContainerHeight: number; - componentWidth: number; - isSuccessWidth: number; - isDragEnter: boolean; -} +import reducer, { + IFileUploadState, + SET_COMPONENT_WIDTH, + SET_HEIGHT, + SET_INITIAL_HEIGHT_PLUS_VALUES, + SET_INITIAL_HEIGHT_VALUES, + SET_IS_DRAG_ENTER, + SET_IS_SUCCESS_WIDTH, + SET_LOADING_CONTAINER_HEIGHT, + SET_OPACITY_IS_FAILURE, + SET_OPACITY_IS_SUCCESS, + SET_OPACITY_LOADING, + SET_POSITION_TOP_LOADING, + SET_TOTAL_HEIGHT_PLUS, + LOADING_RESTORE, + IS_FAILURE_RESTORE, + IS_SUCCESS_RESTORE, +} from './reducer'; const MESSAGE_DURATION = 1500; -const MAX_HEIGHT = 9000; +const SUCCESS_MESSAGE='Completed'; +const FAILURE_MESSAGE='Something went wrong'; +const TITLE='Drop your file here, or click to browse'; +const SUBTITLE='Admits any kind of file'; const TRANSITION_HEIGHT_ANIMATION_DURATION = 500; const FIRST_FILE = 0; const PADDING = 10; const MARGIN = 10; -const SET_HEIGHT = 'SET_HEIGHT'; -const SET_MAX_HEIGHT = 'SET_MAX_HEIGHT'; -const SET_TOTAL_HEIGHT = 'SET_TOTAL_HEIGHT'; -const SET_COMPONENT_WIDTH = 'SET_COMPONENT_WIDTH'; -const SET_TOTAL_HEIGHT_PLUS = 'SET_TOTAL_HEIGHT_PLUS'; -const SET_POSITION_TOP_LOADING = 'SET_POSITION_TOP_LOADING'; -const SET_IS_SUCCESS_WIDTH = 'SET_IS_SUCCESS_WIDTH'; -const SET_OPACITY_LOADING = 'SET_OPACITY_LOADING'; -const SET_POSITION_LOADING = 'SET_POSITION_LOADING'; -const SET_OPACITY_IS_SUCCESS = 'SET_OPACITY_IS_SUCCESS'; -const SET_POSITION_IS_SUCCESS = 'SET_POSITION_IS_SUCCESS'; -const SET_OPACITY_IS_FAILURE = 'SET_OPACITY_IS_FAILURE'; -const SET_POSITION_IS_FAILURE = 'SET_POSITION_IS_FAILURE'; -const SET_LOADING_CONTAINER_HEIGHT = 'SET_LOADING_CONTAINER_HEIGHT'; -const SET_IS_DRAG_ENTER = 'SET_IS_DRAG_ENTER'; -const LOADING_FADE_OUT = 'LOADING_FADE_OUT'; -const LOADING_RESTORE = 'LOADING_RESTORE'; -const IS_SUCCESS_FADE_OUT = 'IS_SUCCESS_FADE_OUT'; -const IS_SUCCESS_RESTORE = 'IS_SUCCESS_RESTORE'; -const IS_FAILURE_FADE_OUT = 'IS_FAILURE_FADE_OUT'; -const IS_FAILURE_RESTORE = 'IS_FAILURE_RESTORE'; -const SET_INITIAL_HEIGHT_VALUES = 'SET_INITIAL_HEIGHT_VALUES'; -const SET_INITIAL_HEIGHT_PLUS_VALUES = 'SET_INITIAL_HEIGHT_PLUS_VALUES'; - -type Action = - | { - type: 'SET_HEIGHT' | 'SET_MAX_HEIGHT'; - value: number | undefined; - } - | { - type: - | 'SET_TOTAL_HEIGHT' - | 'SET_COMPONENT_WIDTH' - | 'SET_TOTAL_HEIGHT_PLUS' - | 'SET_POSITION_TOP_LOADING' - | 'SET_IS_SUCCESS_WIDTH' - | 'SET_OPACITY_LOADING' - | 'SET_OPACITY_IS_SUCCESS' - | 'SET_OPACITY_IS_FAILURE' - | 'SET_LOADING_CONTAINER_HEIGHT' - | 'SET_INITIAL_HEIGHT_VALUES'; - value: number; - } - | { - type: - | 'SET_POSITION_LOADING' - | 'SET_POSITION_IS_SUCCESS' - | 'SET_POSITION_IS_FAILURE' - | 'SET_IS_DRAG_ENTER'; - value: boolean; - } - | { - type: - | 'LOADING_FADE_OUT' - | 'LOADING_RESTORE' - | 'IS_SUCCESS_FADE_OUT' - | 'IS_SUCCESS_RESTORE' - | 'IS_FAILURE_FADE_OUT' - | 'IS_FAILURE_RESTORE' - | 'SET_INITIAL_HEIGHT_PLUS_VALUES'; - }; - -const reducer = (state: IState, action: Action): IState => { - switch (action.type) { - case SET_HEIGHT: - return { - ...state, - height: action.value, - }; - case SET_MAX_HEIGHT: - return { - ...state, - maxHeight: action.value, - }; - case SET_TOTAL_HEIGHT: - return { - ...state, - totalHeight: action.value, - }; - case SET_COMPONENT_WIDTH: - return { - ...state, - componentWidth: action.value, - }; - case SET_TOTAL_HEIGHT_PLUS: - return { - ...state, - totalHeightPlus: action.value, - }; - case SET_POSITION_TOP_LOADING: - return { - ...state, - positionTopLoading: action.value, - }; - case SET_IS_SUCCESS_WIDTH: - return { - ...state, - isSuccessWidth: action.value, - }; - case SET_OPACITY_LOADING: - return { - ...state, - loading: { - ...state.loading, - opacity: action.value, - }, - }; - case SET_POSITION_LOADING: - return { - ...state, - loading: { - ...state.loading, - position: action.value, - }, - }; - case SET_OPACITY_IS_SUCCESS: - return { - ...state, - isSuccess: { - ...state.isSuccess, - opacity: action.value, - }, - }; - case SET_POSITION_IS_SUCCESS: - return { - ...state, - isSuccess: { - ...state.isSuccess, - position: action.value, - }, - }; - case SET_OPACITY_IS_FAILURE: - return { - ...state, - isFailure: { - ...state.isFailure, - opacity: action.value, - }, - }; - case SET_POSITION_IS_FAILURE: - return { - ...state, - isFailure: { - ...state.isFailure, - position: action.value, - }, - }; - case SET_LOADING_CONTAINER_HEIGHT: - return { - ...state, - loadingContainerHeight: action.value, - }; - case SET_IS_DRAG_ENTER: - return { - ...state, - isDragEnter: action.value, - }; - case LOADING_FADE_OUT: - return { - ...state, - loading: { - ...state.loading, - opacity: 0, - position: true, - }, - }; - case LOADING_RESTORE: - return { - ...state, - loading: { - ...state.loading, - opacity: 1, - position: false, - }, - }; - case IS_SUCCESS_FADE_OUT: - return { - ...state, - isSuccess: { - ...state.isSuccess, - opacity: 0, - position: true, - }, - }; - case IS_SUCCESS_RESTORE: - return { - ...state, - isSuccess: { - ...state.isSuccess, - opacity: 1, - position: false, - }, - }; - case IS_FAILURE_FADE_OUT: - return { - ...state, - isFailure: { - ...state.isFailure, - opacity: 0, - position: true, - }, - }; - case IS_FAILURE_RESTORE: - return { - ...state, - isFailure: { - ...state.isFailure, - opacity: 1, - position: false, - }, - }; - case SET_INITIAL_HEIGHT_VALUES: - return { - ...state, - maxHeight: action.value, - totalHeight: action.value, - }; - case SET_INITIAL_HEIGHT_PLUS_VALUES: - return { - ...state, - height: undefined, - maxHeight: MAX_HEIGHT, - }; - default: - return state; - } -}; - export interface IFileUploadProps { - title: string; - subTitle: string; - minHeight: number; + /** the title message; default value: 'Drop your file here, or click to browse' */ + title?: string; + /** the subtitle message; default value: 'Admits any kind of file' */ + subTitle?: string; + /** minimum height for the component; optional */ + minHeight?: number; + /** minimum width for the component; optional */ minWidth?: number; - setBase64: (base64StringFile: string) => void; - isUploading: boolean; - isSuccess: boolean; - isFailure: boolean; - successMessage: string; - failureMessage: string; - disabled: boolean; - setIsUploading: React.Dispatch>; - setIsSuccess: React.Dispatch>; - setIsFailure: React.Dispatch>; + /** + * function to process the file read and transformed to a base64 string; default: does nothing + * @param {string} base64StringFile the file read and transformed to a base64 string + */ + doWithBase64StringFile?: (base64StringFile: string) => void; + /** message of the bottom panel to inform of the success of the operation of reading the file content; default value: 'Completed' */ + successMessage?: string; + /** message of the bottom panel to inform of the failure of the operation of reading the file content; default value: 'Something went wrong' */ + failureMessage?: string; + /** if true, disables the component functionality; default value: false */ + isDisabled?: boolean; + /** time in ms of the presence of the bottom panel informing the result of the operation (sucess or failure); default value: 1500 */ messageDuration?: number; + /** if true, failure message will appear even after success operation; its purpose is to test the appearance of the failure message during development */ + isTestIsFailure?:boolean; + /** height and fade in-fade out animation duration in ms; default value: 500 */ + animationDuration?:number; } export const FileUpload: React.FC = ({ - title, - subTitle, + title=TITLE, + subTitle=SUBTITLE, minHeight, minWidth, - setBase64, - isUploading, - isSuccess, - isFailure, - successMessage, - failureMessage, - disabled, - setIsUploading, - setIsSuccess, - setIsFailure, + doWithBase64StringFile = (base64StringFile: string) => null, + successMessage=SUCCESS_MESSAGE, + failureMessage=FAILURE_MESSAGE, + isDisabled=false, messageDuration = MESSAGE_DURATION, + isTestIsFailure, + animationDuration=TRANSITION_HEIGHT_ANIMATION_DURATION, }): React.ReactElement => { - const initState: IState = { + const [isUploading, setIsUploading] = useState(false); + const [isSuccess, setIsSuccess] = useState(false); + const [isFailure, setIsFailure] = useState(false); + const initState: IFileUploadState = { height: undefined, totalHeight: 0, totalHeightPlus: 0, @@ -336,20 +118,75 @@ export const FileUpload: React.FC = ({ const workerRef = useRef(); const base64StringFileRef = useRef(''); const previousIsSuccessValue = useRef(isSuccess); - /** - * this is to execute setBase64 function after the animation finishes + * ref to the most outer container, which contains everything else */ + const containerRef = useRef(null); + const loadingContainerRef = useRef(null); + + const onDrop = useCallback((acceptedFiles: File[]) => { + setFileName(acceptedFiles[FIRST_FILE].name); + setIsUploading(true); + setIsSuccess(false); + setIsFailure(false); + acceptedFiles.forEach((file) => { + const workerInstance = worker(); + workerRef.current = workerInstance; + workerInstance.onmessage = (e: any) => { + const { base64StringFile } = e.data; + if (base64StringFile === NO_BASE64STRINGFILE|| isTestIsFailure) { + workerRef.current?.terminate(); + setIsFailure(true); + setIsSuccess(false); + setIsUploading(false); + setTimeout(() => { + if (isMounted.current) setIsFailure(false); + }, messageDuration); + } else if (base64StringFile !== undefined) { + workerRef.current?.terminate(); + base64StringFileRef.current = base64StringFile; + setIsSuccess(true); + setIsFailure(false); + setIsUploading(false); + setTimeout(() => { + if (isMounted.current) { + setIsSuccess(false); + } + }, messageDuration); + } + }; + workerInstance.postMessage({ file }); + dispatch({ type: SET_IS_DRAG_ENTER, value: false }); + }); + }, [isTestIsFailure]); + + const onDragEnter = useCallback((event: React.DragEvent) => { + event.preventDefault(); + dispatch({ type: SET_IS_DRAG_ENTER, value: true }); + }, []); + const onDragLeave = useCallback((event: React.DragEvent) => { + event.preventDefault(); + dispatch({ type: SET_IS_DRAG_ENTER, value: false }); + }, []); + + const { getRootProps, getInputProps, rootRef } = useDropzone({ + onDrop, + onDragEnter, + onDragLeave, + disabled:isDisabled, + }); + + // execute setBase64 function after the animation finishes useEffect(() => { if (previousIsSuccessValue.current) { setTimeout(() => { - setBase64(base64StringFileRef.current); - }, TRANSITION_HEIGHT_ANIMATION_DURATION); + doWithBase64StringFile(base64StringFileRef.current); + }, animationDuration); } previousIsSuccessValue.current = isSuccess; - }, [isSuccess]); + }, [isSuccess,animationDuration]); - // this is to calculate (set) some values after the first render + // calculate (set) some values after the first render useEffect(() => { if (containerRef.current?.scrollHeight) { const innerContentHeight = @@ -367,7 +204,7 @@ export const FileUpload: React.FC = ({ }, []); useEffect(() => { - // this is to set some values the first time when the component it's expanded + // set some values the first time when the component it's expanded if ( state.height === undefined && (isUploading || isSuccess || isFailure) @@ -387,7 +224,7 @@ export const FileUpload: React.FC = ({ }); } } - // this is to calculate and set the width of the success and failure container component + // calculate and set the width of the success and failure container component if (isSuccess || isFailure) { const width = containerRef.current?.getBoundingClientRect().width; if (width) { @@ -397,7 +234,7 @@ export const FileUpload: React.FC = ({ }); } } - // this sets height of the component, is used to transition between heights. + // sets height of the component, is used to transition between heights. if (isUploading || isSuccess || isFailure) { if (state.totalHeightPlus) { dispatch({ type: SET_HEIGHT, value: state.totalHeightPlus }); @@ -407,7 +244,7 @@ export const FileUpload: React.FC = ({ } else if (state.totalHeight) { dispatch({ type: SET_HEIGHT, value: state.totalHeight }); } - // this is to calculate and set isuploading container panel. + // calculate and set isUploading container panel. if ( isUploading && !isFailure && @@ -457,7 +294,7 @@ export const FileUpload: React.FC = ({ }; }, [isSuccess]); - // this is used to resize bottom panel with when resizing window browser + // resize bottom panel width when resizing window browser useLayoutEffect(() => { function updateSize() { if (rootRef.current?.clientWidth) { @@ -469,8 +306,8 @@ export const FileUpload: React.FC = ({ }); } if (isSuccess || isFailure) { - const width = - containerRef.current?.getBoundingClientRect().width; + const width = containerRef.current?.getBoundingClientRect() + .width; if (width) { dispatch({ type: SET_IS_SUCCESS_WIDTH, @@ -484,66 +321,14 @@ export const FileUpload: React.FC = ({ return () => window.removeEventListener('resize', updateSize); }, [isSuccess, isFailure]); - const containerRef = useRef(null); - const loadingContainerRef = useRef(null); - - const onDrop = useCallback((acceptedFiles: File[]) => { - setFileName(acceptedFiles[FIRST_FILE].name); - setIsUploading(true); - setIsSuccess(false); - setIsFailure(false); - acceptedFiles.forEach((file) => { - const workerInstance = worker(); - workerRef.current = workerInstance; - workerInstance.onmessage = (e: any) => { - const { base64StringFile } = e.data; - if (base64StringFile === NO_BASE64STRINGFILE) { - workerRef.current?.terminate(); - setIsFailure(true); - setIsSuccess(false); - setIsUploading(false); - setTimeout(() => { - if (isMounted.current) setIsFailure(false); - }, messageDuration); - } else if (base64StringFile !== undefined) { - workerRef.current?.terminate(); - base64StringFileRef.current = base64StringFile; - setIsSuccess(true); - setIsFailure(false); - setIsUploading(false); - setTimeout(() => { - if (isMounted.current) { - setIsSuccess(false); - } - }, messageDuration); - } - }; - workerInstance.postMessage({ file }); - dispatch({ type: SET_IS_DRAG_ENTER, value: false }); - }); - }, []); - const onDragEnter = useCallback((event: React.DragEvent) => { - event.preventDefault(); - dispatch({ type: SET_IS_DRAG_ENTER, value: true }); - }, []); - const onDragLeave = useCallback((event: React.DragEvent) => { - event.preventDefault(); - dispatch({ type: SET_IS_DRAG_ENTER, value: false }); - }, []); - const { getRootProps, getInputProps, rootRef } = useDropzone({ - onDrop, - onDragEnter, - onDragLeave, - disabled, - }); - - const renderChild = (): React.ReactElement | undefined => { + const renderBottomPanelContent = (): React.ReactElement | undefined => { if (isFailure) { return ( ); } @@ -553,6 +338,7 @@ export const FileUpload: React.FC = ({ message={successMessage} iconColor={MainTheme.colors.statusColors.green} IconToShow={CheckCircle} + transitionDuration={animationDuration} /> ); } @@ -584,6 +370,8 @@ export const FileUpload: React.FC = ({ overflow="hidden" height={state.height} margin={`${MARGIN}px`} + isWidthFitContent + transitionDuration={animationDuration} > = ({ padding: '10px', margin: `${MARGIN}px`, })} + transitionDuration={animationDuration} > {state.isDragEnter ? ( @@ -646,8 +435,9 @@ export const FileUpload: React.FC = ({ : undefined } withFlexSpaceBetween={isFailure || isSuccess ? true : undefined} + transitionDuration={animationDuration} > - {renderChild()} + {renderBottomPanelContent()} ); diff --git a/src/Containers/FileUpload/IsFailureIsSuccessPanel.tsx b/src/Containers/FileUpload/IsFailureIsSuccessPanel.tsx index 502268ebf..b77982d86 100644 --- a/src/Containers/FileUpload/IsFailureIsSuccessPanel.tsx +++ b/src/Containers/FileUpload/IsFailureIsSuccessPanel.tsx @@ -1,16 +1,16 @@ import React, { useState, useEffect } from 'react'; import { TextLayout } from '@Layouts'; import { StyledIcon } from '@styled-icons/styled-icon'; -import { Container, Icon } from './StyledComponents'; +import { Container, Icon, IContainerProps } from './StyledComponents'; -interface IIsFailureIsSuccessPanelProps { +interface IIsFailureIsSuccessPanelProps extends IContainerProps{ IconToShow: StyledIcon; iconColor: string; message: string; } export const IsFailureIsSuccessPanel: React.FC = - ({ IconToShow, iconColor, message }): React.ReactElement => { + ({ IconToShow, iconColor, message,...props }): React.ReactElement => { const [opacity, setOpacity] = useState(0); useEffect(() => { setOpacity(1); @@ -21,6 +21,7 @@ export const IsFailureIsSuccessPanel: React.FC = flexGrow margin="10px" opacity={opacity} + {...props} > {message} diff --git a/src/Containers/FileUpload/StyledComponents.ts b/src/Containers/FileUpload/StyledComponents.ts index 55e93f9b9..f5263c84a 100644 --- a/src/Containers/FileUpload/StyledComponents.ts +++ b/src/Containers/FileUpload/StyledComponents.ts @@ -7,6 +7,7 @@ export interface IContainerProps { withFlexSpaceBetween?: boolean; withBorder?: boolean; width?: number; + isWidthFitContent?:boolean; padding?: string; isDragEnter?: boolean; backgroundColor?: string; @@ -19,6 +20,8 @@ export interface IContainerProps { margin?: string; positionTop?: number; flexGrow?: boolean; + /** transition duration in ms; applied on height and opacity properties; */ + transitionDuration:number; } export const Container = styled.div` @@ -27,6 +30,7 @@ export const Container = styled.div` withFlexCenter, withBorder, width, + isWidthFitContent, padding, isDragEnter, withFlexSpaceBetween, @@ -40,6 +44,7 @@ export const Container = styled.div` margin, positionTop, flexGrow, + transitionDuration, }): string => ` ${borderRadius ? `border-radius:${borderRadius};` : 'border-radius:10px;'} ${ @@ -52,6 +57,7 @@ border:2px ${dashed ? 'dashed' : 'solid'} rgba(128,128,128,.8); ${withFlexCenter ? flex('center') : ''} ${withFlexSpaceBetween ? flex('space-between', 'center') : ''} ${width ? `width:${width}px;` : ''} +${isWidthFitContent ? `width:fit-content;` : ''} ${padding ? `padding:${padding};` : ''} ${ isDragEnter @@ -81,8 +87,10 @@ ${overflow ? `overflow:${overflow};` : ''} ${position ? `position:absolute;top:${positionTop}px;` : ''} ${margin ? `margin:${margin};` : ''} ${flexGrow ? `flex:1;` : ''} + +transition:height ${transitionDuration}ms,opacity ${transitionDuration}ms,max-height ${transitionDuration*10}ms; `} - transition:height .5s,opacity .5s,max-height 5s; + `; interface IIconProps { diff --git a/src/Containers/FileUpload/reducer.ts b/src/Containers/FileUpload/reducer.ts new file mode 100644 index 000000000..1e8ae365e --- /dev/null +++ b/src/Containers/FileUpload/reducer.ts @@ -0,0 +1,251 @@ +const MAX_HEIGHT = 9000; + +interface IOptions { + position: boolean; + opacity: number; +} + +export interface IFileUploadState { + height: number | undefined; + totalHeight: number; + totalHeightPlus: number; + maxHeight: number | undefined; + loading: IOptions; + isSuccess: IOptions; + isFailure: IOptions; + positionTopLoading: number; + loadingContainerHeight: number; + componentWidth: number; + isSuccessWidth: number; + isDragEnter: boolean; +} + +export const SET_HEIGHT = 'SET_HEIGHT'; +export const SET_MAX_HEIGHT = 'SET_MAX_HEIGHT'; +export const SET_TOTAL_HEIGHT = 'SET_TOTAL_HEIGHT'; +export const SET_COMPONENT_WIDTH = 'SET_COMPONENT_WIDTH'; +export const SET_TOTAL_HEIGHT_PLUS = 'SET_TOTAL_HEIGHT_PLUS'; +export const SET_POSITION_TOP_LOADING = 'SET_POSITION_TOP_LOADING'; +export const SET_IS_SUCCESS_WIDTH = 'SET_IS_SUCCESS_WIDTH'; +export const SET_OPACITY_LOADING = 'SET_OPACITY_LOADING'; +export const SET_POSITION_LOADING = 'SET_POSITION_LOADING'; +export const SET_OPACITY_IS_SUCCESS = 'SET_OPACITY_IS_SUCCESS'; +export const SET_POSITION_IS_SUCCESS = 'SET_POSITION_IS_SUCCESS'; +export const SET_OPACITY_IS_FAILURE = 'SET_OPACITY_IS_FAILURE'; +export const SET_POSITION_IS_FAILURE = 'SET_POSITION_IS_FAILURE'; +export const SET_LOADING_CONTAINER_HEIGHT = 'SET_LOADING_CONTAINER_HEIGHT'; +export const SET_IS_DRAG_ENTER = 'SET_IS_DRAG_ENTER'; +export const LOADING_FADE_OUT = 'LOADING_FADE_OUT'; +export const LOADING_RESTORE = 'LOADING_RESTORE'; +export const IS_SUCCESS_FADE_OUT = 'IS_SUCCESS_FADE_OUT'; +export const IS_SUCCESS_RESTORE = 'IS_SUCCESS_RESTORE'; +export const IS_FAILURE_FADE_OUT = 'IS_FAILURE_FADE_OUT'; +export const IS_FAILURE_RESTORE = 'IS_FAILURE_RESTORE'; +export const SET_INITIAL_HEIGHT_VALUES = 'SET_INITIAL_HEIGHT_VALUES'; +export const SET_INITIAL_HEIGHT_PLUS_VALUES = 'SET_INITIAL_HEIGHT_PLUS_VALUES'; + +type Action = + | { + type: 'SET_HEIGHT' | 'SET_MAX_HEIGHT'; + value: number | undefined; + } + | { + type: + | 'SET_TOTAL_HEIGHT' + | 'SET_COMPONENT_WIDTH' + | 'SET_TOTAL_HEIGHT_PLUS' + | 'SET_POSITION_TOP_LOADING' + | 'SET_IS_SUCCESS_WIDTH' + | 'SET_OPACITY_LOADING' + | 'SET_OPACITY_IS_SUCCESS' + | 'SET_OPACITY_IS_FAILURE' + | 'SET_LOADING_CONTAINER_HEIGHT' + | 'SET_INITIAL_HEIGHT_VALUES'; + value: number; + } + | { + type: + | 'SET_POSITION_LOADING' + | 'SET_POSITION_IS_SUCCESS' + | 'SET_POSITION_IS_FAILURE' + | 'SET_IS_DRAG_ENTER'; + value: boolean; + } + | { + type: + | 'LOADING_FADE_OUT' + | 'LOADING_RESTORE' + | 'IS_SUCCESS_FADE_OUT' + | 'IS_SUCCESS_RESTORE' + | 'IS_FAILURE_FADE_OUT' + | 'IS_FAILURE_RESTORE' + | 'SET_INITIAL_HEIGHT_PLUS_VALUES'; + }; + +const reducer = (state: IFileUploadState, action: Action): IFileUploadState => { + switch (action.type) { + case SET_HEIGHT: + return { + ...state, + height: action.value, + }; + case SET_MAX_HEIGHT: + return { + ...state, + maxHeight: action.value, + }; + case SET_TOTAL_HEIGHT: + return { + ...state, + totalHeight: action.value, + }; + case SET_COMPONENT_WIDTH: + return { + ...state, + componentWidth: action.value, + }; + case SET_TOTAL_HEIGHT_PLUS: + return { + ...state, + totalHeightPlus: action.value, + }; + case SET_POSITION_TOP_LOADING: + return { + ...state, + positionTopLoading: action.value, + }; + case SET_IS_SUCCESS_WIDTH: + return { + ...state, + isSuccessWidth: action.value, + }; + case SET_OPACITY_LOADING: + return { + ...state, + loading: { + ...state.loading, + opacity: action.value, + }, + }; + case SET_POSITION_LOADING: + return { + ...state, + loading: { + ...state.loading, + position: action.value, + }, + }; + case SET_OPACITY_IS_SUCCESS: + return { + ...state, + isSuccess: { + ...state.isSuccess, + opacity: action.value, + }, + }; + case SET_POSITION_IS_SUCCESS: + return { + ...state, + isSuccess: { + ...state.isSuccess, + position: action.value, + }, + }; + case SET_OPACITY_IS_FAILURE: + return { + ...state, + isFailure: { + ...state.isFailure, + opacity: action.value, + }, + }; + case SET_POSITION_IS_FAILURE: + return { + ...state, + isFailure: { + ...state.isFailure, + position: action.value, + }, + }; + case SET_LOADING_CONTAINER_HEIGHT: + return { + ...state, + loadingContainerHeight: action.value, + }; + case SET_IS_DRAG_ENTER: + return { + ...state, + isDragEnter: action.value, + }; + case LOADING_FADE_OUT: + return { + ...state, + loading: { + ...state.loading, + opacity: 0, + position: true, + }, + }; + case LOADING_RESTORE: + return { + ...state, + loading: { + ...state.loading, + opacity: 1, + position: false, + }, + }; + case IS_SUCCESS_FADE_OUT: + return { + ...state, + isSuccess: { + ...state.isSuccess, + opacity: 0, + position: true, + }, + }; + case IS_SUCCESS_RESTORE: + return { + ...state, + isSuccess: { + ...state.isSuccess, + opacity: 1, + position: false, + }, + }; + case IS_FAILURE_FADE_OUT: + return { + ...state, + isFailure: { + ...state.isFailure, + opacity: 0, + position: true, + }, + }; + case IS_FAILURE_RESTORE: + return { + ...state, + isFailure: { + ...state.isFailure, + opacity: 1, + position: false, + }, + }; + case SET_INITIAL_HEIGHT_VALUES: + return { + ...state, + maxHeight: action.value, + totalHeight: action.value, + }; + case SET_INITIAL_HEIGHT_PLUS_VALUES: + return { + ...state, + height: undefined, + maxHeight: MAX_HEIGHT, + }; + default: + return state; + } +}; + +export default reducer; diff --git a/src/Inputs/Button/Button.tsx b/src/Inputs/Button/Button.tsx index a8833d571..cc5b1e48a 100644 --- a/src/Inputs/Button/Button.tsx +++ b/src/Inputs/Button/Button.tsx @@ -55,7 +55,7 @@ export const Button: React.FC = ({ hasText={children} /> )} - {children && {children}} + {children && {children}} {isLoading && } ); @@ -140,10 +140,10 @@ const Icon = styled.svg` `} `; -const Content = styled.span<{ loading: boolean }>` +const Content = styled.span<{ isLoading: boolean }>` ${transition(['transform', 'opacity'])} - ${({ loading }): string => - loading + ${({ isLoading }): string => + isLoading ? ` transform: translate3d(0,80%,0); opacity: 0; From ee3f36097e5b5f10ac9ba52867a04afa5a685d87 Mon Sep 17 00:00:00 2001 From: roggc Date: Sun, 2 Jan 2022 13:04:26 +0100 Subject: [PATCH 02/20] multiple file upload --- src/Containers/FileUpload/FileUpload.tsx | 153 ++++++++++++----------- 1 file changed, 82 insertions(+), 71 deletions(-) diff --git a/src/Containers/FileUpload/FileUpload.tsx b/src/Containers/FileUpload/FileUpload.tsx index 17949a9b4..30759e6db 100644 --- a/src/Containers/FileUpload/FileUpload.tsx +++ b/src/Containers/FileUpload/FileUpload.tsx @@ -9,7 +9,7 @@ import React, { import styled from 'styled-components'; import { flex } from '@Utils/Mixins'; import { TextLayout } from '@Layouts'; -import { useDropzone } from 'react-dropzone'; +import Dropzone, { useDropzone } from 'react-dropzone'; import { Image } from '@styled-icons/fa-solid/Image'; import { CheckCircle } from '@styled-icons/fa-solid/CheckCircle'; import { TimesCircle } from '@styled-icons/fa-solid/TimesCircle'; @@ -43,18 +43,19 @@ import reducer, { } from './reducer'; const MESSAGE_DURATION = 1500; -const SUCCESS_MESSAGE='Completed'; -const FAILURE_MESSAGE='Something went wrong'; -const TITLE='Drop your file here, or click to browse'; -const SUBTITLE='Admits any kind of file'; -const TRANSITION_HEIGHT_ANIMATION_DURATION = 500; +const SUCCESS_MESSAGE = 'Completed'; +const FAILURE_MESSAGE = 'Something went wrong'; +const TITLE = 'Drop your files here, or click to browse'; +const SUBTITLE = 'Admits any kind of files'; +const TRANSITION_HEIGHT_ANIMATION_DURATION = 200; const FIRST_FILE = 0; +const ONLY_ONE_FILE=1; const PADDING = 10; const MARGIN = 10; export interface IFileUploadProps { - /** the title message; default value: 'Drop your file here, or click to browse' */ + /** the title message; default value: 'Drop your files here, or click to browse' */ title?: string; /** the subtitle message; default value: 'Admits any kind of file' */ subTitle?: string; @@ -62,8 +63,8 @@ export interface IFileUploadProps { minHeight?: number; /** minimum width for the component; optional */ minWidth?: number; - /** - * function to process the file read and transformed to a base64 string; default: does nothing + /** + * function to process the file read and transformed to a base64 string; default: does nothing * @param {string} base64StringFile the file read and transformed to a base64 string */ doWithBase64StringFile?: (base64StringFile: string) => void; @@ -76,23 +77,23 @@ export interface IFileUploadProps { /** time in ms of the presence of the bottom panel informing the result of the operation (sucess or failure); default value: 1500 */ messageDuration?: number; /** if true, failure message will appear even after success operation; its purpose is to test the appearance of the failure message during development */ - isTestIsFailure?:boolean; - /** height and fade in-fade out animation duration in ms; default value: 500 */ - animationDuration?:number; + isTestIsFailure?: boolean; + /** height and fade in-fade out animation duration in ms; default value: 200 */ + animationDuration?: number; } export const FileUpload: React.FC = ({ - title=TITLE, - subTitle=SUBTITLE, + title = TITLE, + subTitle = SUBTITLE, minHeight, minWidth, doWithBase64StringFile = (base64StringFile: string) => null, - successMessage=SUCCESS_MESSAGE, - failureMessage=FAILURE_MESSAGE, - isDisabled=false, + successMessage = SUCCESS_MESSAGE, + failureMessage = FAILURE_MESSAGE, + isDisabled = false, messageDuration = MESSAGE_DURATION, isTestIsFailure, - animationDuration=TRANSITION_HEIGHT_ANIMATION_DURATION, + animationDuration = TRANSITION_HEIGHT_ANIMATION_DURATION, }): React.ReactElement => { const [isUploading, setIsUploading] = useState(false); const [isSuccess, setIsSuccess] = useState(false); @@ -116,25 +117,33 @@ export const FileUpload: React.FC = ({ const [fileName, setFileName] = useState(''); const workerRef = useRef(); - const base64StringFileRef = useRef(''); - const previousIsSuccessValue = useRef(isSuccess); /** * ref to the most outer container, which contains everything else */ const containerRef = useRef(null); const loadingContainerRef = useRef(null); - const onDrop = useCallback((acceptedFiles: File[]) => { - setFileName(acceptedFiles[FIRST_FILE].name); - setIsUploading(true); - setIsSuccess(false); - setIsFailure(false); - acceptedFiles.forEach((file) => { + /** + * recursive function; reads files sequentially; + */ + const onDrop = useCallback( + (acceptedFiles: File[]) => { + const file = acceptedFiles[FIRST_FILE]; + setFileName(file.name); + setIsUploading(true); + setIsSuccess(false); + setIsFailure(false); const workerInstance = worker(); workerRef.current = workerInstance; workerInstance.onmessage = (e: any) => { const { base64StringFile } = e.data; - if (base64StringFile === NO_BASE64STRINGFILE|| isTestIsFailure) { + if(base64StringFile===undefined){ + return + } + if ( + base64StringFile === NO_BASE64STRINGFILE || + isTestIsFailure + ) { workerRef.current?.terminate(); setIsFailure(true); setIsSuccess(false); @@ -144,21 +153,25 @@ export const FileUpload: React.FC = ({ }, messageDuration); } else if (base64StringFile !== undefined) { workerRef.current?.terminate(); - base64StringFileRef.current = base64StringFile; + doWithBase64StringFile(base64StringFile); setIsSuccess(true); setIsFailure(false); setIsUploading(false); setTimeout(() => { if (isMounted.current) { setIsSuccess(false); + if(acceptedFiles.length>ONLY_ONE_FILE){ + onDrop(acceptedFiles.slice(1)); + } } }, messageDuration); } }; workerInstance.postMessage({ file }); dispatch({ type: SET_IS_DRAG_ENTER, value: false }); - }); - }, [isTestIsFailure]); + }, + [isTestIsFailure], + ); const onDragEnter = useCallback((event: React.DragEvent) => { event.preventDefault(); @@ -173,19 +186,9 @@ export const FileUpload: React.FC = ({ onDrop, onDragEnter, onDragLeave, - disabled:isDisabled, + disabled: isDisabled, }); - // execute setBase64 function after the animation finishes - useEffect(() => { - if (previousIsSuccessValue.current) { - setTimeout(() => { - doWithBase64StringFile(base64StringFileRef.current); - }, animationDuration); - } - previousIsSuccessValue.current = isSuccess; - }, [isSuccess,animationDuration]); - // calculate (set) some values after the first render useEffect(() => { if (containerRef.current?.scrollHeight) { @@ -373,36 +376,44 @@ export const FileUpload: React.FC = ({ isWidthFitContent transitionDuration={animationDuration} > - - - {state.isDragEnter ? ( - - ) : ( - - )} - - {title} - - - {subTitle} - - - - + + {() => ( + + + {state.isDragEnter ? ( + + ) : ( + + )} + + {title} + + + {subTitle} + + + + + )} + Date: Sun, 2 Jan 2022 13:07:04 +0100 Subject: [PATCH 03/20] jsdoc --- src/Containers/FileUpload/FileUpload.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Containers/FileUpload/FileUpload.tsx b/src/Containers/FileUpload/FileUpload.tsx index 30759e6db..1561925ac 100644 --- a/src/Containers/FileUpload/FileUpload.tsx +++ b/src/Containers/FileUpload/FileUpload.tsx @@ -82,6 +82,7 @@ export interface IFileUploadProps { animationDuration?: number; } +/** multiple file upload */ export const FileUpload: React.FC = ({ title = TITLE, subTitle = SUBTITLE, From d35e320cd99477a63ded5499c5339d6d89c7d098 Mon Sep 17 00:00:00 2001 From: roggc Date: Mon, 3 Jan 2022 15:38:12 +0100 Subject: [PATCH 04/20] parallel uploading without animation --- src/Containers/FileUpload/FileUpload.tsx | 695 +++++++++++++++-------- src/Containers/FileUpload/reducer.ts | 225 +++++--- src/Containers/FileUpload/worker.js | 2 +- 3 files changed, 611 insertions(+), 311 deletions(-) diff --git a/src/Containers/FileUpload/FileUpload.tsx b/src/Containers/FileUpload/FileUpload.tsx index 1561925ac..3fde7a39e 100644 --- a/src/Containers/FileUpload/FileUpload.tsx +++ b/src/Containers/FileUpload/FileUpload.tsx @@ -40,6 +40,9 @@ import reducer, { LOADING_RESTORE, IS_FAILURE_RESTORE, IS_SUCCESS_RESTORE, + ADD_LOADING_IS_SUCCESS_IS_FAILURE, + RESET_LOADING_IS_SUCCESS_IS_FAILURE, + REMOVE_LOADING_IS_SUCCESS_IS_FAILURE, } from './reducer'; const MESSAGE_DURATION = 1500; @@ -48,12 +51,34 @@ const FAILURE_MESSAGE = 'Something went wrong'; const TITLE = 'Drop your files here, or click to browse'; const SUBTITLE = 'Admits any kind of files'; const TRANSITION_HEIGHT_ANIMATION_DURATION = 200; -const FIRST_FILE = 0; -const ONLY_ONE_FILE=1; const PADDING = 10; const MARGIN = 10; +interface ISpecificValues { + value: boolean; + opacity: number; + isPosition: boolean; +} + +interface IValue { + isSuccess: ISpecificValues; + isFailure: ISpecificValues; + isUploading: ISpecificValues; + name: string; + worker: Worker; + file: File; +} + +interface IInformativePanelsState { + values: IValue[]; + /** index affected */ + index: number; + name: string; + makeItDisappear: boolean; + startWorkers: boolean; +} + export interface IFileUploadProps { /** the title message; default value: 'Drop your files here, or click to browse' */ title?: string; @@ -96,17 +121,22 @@ export const FileUpload: React.FC = ({ isTestIsFailure, animationDuration = TRANSITION_HEIGHT_ANIMATION_DURATION, }): React.ReactElement => { - const [isUploading, setIsUploading] = useState(false); - const [isSuccess, setIsSuccess] = useState(false); - const [isFailure, setIsFailure] = useState(false); + const [informativePanelsState, setInformativePanelsState] = + useState({ + values: [], + index: -1, + makeItDisappear: false, + startWorkers: false, + name: '', + }); const initState: IFileUploadState = { height: undefined, totalHeight: 0, totalHeightPlus: 0, maxHeight: undefined, - loading: { position: !isUploading, opacity: 0 }, - isSuccess: { position: !isSuccess, opacity: 0 }, - isFailure: { position: !isFailure, opacity: 0 }, + loading: [], + isSuccess: [], + isFailure: [], positionTopLoading: 0, loadingContainerHeight: 0, componentWidth: 0, @@ -115,69 +145,202 @@ export const FileUpload: React.FC = ({ }; const [state, dispatch] = useReducer(reducer, initState); const isMounted = useMounted(); - const [fileName, setFileName] = useState(''); - const workerRef = useRef(); + const workerRef = useRef([]); /** * ref to the most outer container, which contains everything else */ const containerRef = useRef(null); const loadingContainerRef = useRef(null); - /** - * recursive function; reads files sequentially; - */ - const onDrop = useCallback( - (acceptedFiles: File[]) => { - const file = acceptedFiles[FIRST_FILE]; - setFileName(file.name); - setIsUploading(true); - setIsSuccess(false); - setIsFailure(false); + const onDrop = useCallback((acceptedFiles: File[]) => { + const valuesToAdd: IValue[] = []; + acceptedFiles.forEach((file) => { const workerInstance = worker(); - workerRef.current = workerInstance; - workerInstance.onmessage = (e: any) => { - const { base64StringFile } = e.data; - if(base64StringFile===undefined){ - return - } - if ( - base64StringFile === NO_BASE64STRINGFILE || - isTestIsFailure - ) { - workerRef.current?.terminate(); - setIsFailure(true); - setIsSuccess(false); - setIsUploading(false); + valuesToAdd.push({ + isSuccess: { value: false, isPosition: false, opacity: 1 }, + isFailure: { value: false, isPosition: false, opacity: 1 }, + isUploading: { value: true, isPosition: false, opacity: 1 }, + name: file.name, + worker: workerInstance, + file, + }); + }); + setInformativePanelsState((prev) => ({ + ...prev, + values: [...prev.values, ...valuesToAdd], + index: -1, + startWorkers: true, + })); + dispatch({ type: SET_IS_DRAG_ENTER, value: false }); + }, []); + + const onWorkerMessage = useCallback( + (e: any) => { + const { base64StringFile, name } = e.data; + if (base64StringFile === undefined) { + return; + } + if (base64StringFile === NO_BASE64STRINGFILE || isTestIsFailure) { + const value = informativePanelsState.values.find( + (value_) => value_.name === name, + ); + if (value) { + value.worker.terminate(); + setInformativePanelsState((prev) => ({ + ...prev, + values: prev.values.map((value_) => { + if (value_.name === value.name) + return { + ...value_, + isSuccess: { + ...value_.isSuccess, + value: false, + }, + isFailure: { + ...value_.isFailure, + value: true, + }, + isUploading: { + ...value_.isUploading, + value: false, + }, + }; + return value_; + }), + })); setTimeout(() => { - if (isMounted.current) setIsFailure(false); + if (isMounted.current) { + setInformativePanelsState((prev) => ({ + ...prev, + values: prev.values.map((value_) => { + if (value_.name === value.name) + return { + ...value_, + isSuccess: { + ...value_.isSuccess, + value: false, + }, + isFailure: { + ...value_.isFailure, + value: false, + }, + isUploading: { + ...value_.isUploading, + value: false, + }, + }; + return value_; + }), + makeItDisappear: true, + name: value.name, + })); + } }, messageDuration); - } else if (base64StringFile !== undefined) { - workerRef.current?.terminate(); + } + } else { + const value = informativePanelsState.values.find( + (value_) => value_.name === name, + ); + if (value) { + value.worker.terminate(); doWithBase64StringFile(base64StringFile); - setIsSuccess(true); - setIsFailure(false); - setIsUploading(false); + setInformativePanelsState((prev) => ({ + ...prev, + values: prev.values.map((value_) => { + if (value_.name === value.name) + return { + ...value_, + isSuccess: { + ...value_.isSuccess, + value: true, + }, + isFailure: { + ...value_.isFailure, + value: false, + }, + isUploading: { + ...value_.isUploading, + value: false, + }, + }; + return value_; + }), + })); setTimeout(() => { if (isMounted.current) { - setIsSuccess(false); - if(acceptedFiles.length>ONLY_ONE_FILE){ - onDrop(acceptedFiles.slice(1)); - } + setInformativePanelsState((prev) => ({ + ...prev, + values: prev.values.map((value_) => { + if (value_.name === value.name) + return { + ...value_, + isSuccess: { + ...value_.isSuccess, + value: false, + }, + isFailure: { + ...value_.isFailure, + value: false, + }, + isUploading: { + ...value_.isUploading, + value: false, + }, + }; + return value_; + }), + makeItDisappear: true, + name: value.name, + })); } }, messageDuration); } - }; - workerInstance.postMessage({ file }); - dispatch({ type: SET_IS_DRAG_ENTER, value: false }); + } }, - [isTestIsFailure], + [informativePanelsState.values, isTestIsFailure], ); + // start workers when files have been droped + useEffect(() => { + if (informativePanelsState.startWorkers) { + setInformativePanelsState((prev) => ({ + ...prev, + startWorkers: false, + })); + informativePanelsState.values.forEach((value) => { + value.worker.onmessage = onWorkerMessage; + value.worker.postMessage({ file: value.file }); + }); + } + }, [informativePanelsState.startWorkers, isTestIsFailure, onWorkerMessage]); + + // make disappear a value (informative panel) + useEffect(() => { + if (informativePanelsState.makeItDisappear) { + // const indexToRemove = informativePanelsState.index; + setInformativePanelsState((prev) => ({ + ...prev, + values: prev.values.filter((value) => { + if (value.name === prev.name) return false; + return true; + }), + index: -1, + makeItDisappear: false, + name: '', + })); + // dispatch({ + // type: REMOVE_LOADING_IS_SUCCESS_IS_FAILURE, + // index: indexToRemove, + // }); + } + }, [informativePanelsState.makeItDisappear]); + const onDragEnter = useCallback((event: React.DragEvent) => { event.preventDefault(); dispatch({ type: SET_IS_DRAG_ENTER, value: true }); }, []); + const onDragLeave = useCallback((event: React.DragEvent) => { event.preventDefault(); dispatch({ type: SET_IS_DRAG_ENTER, value: false }); @@ -191,177 +354,208 @@ export const FileUpload: React.FC = ({ }); // calculate (set) some values after the first render - useEffect(() => { - if (containerRef.current?.scrollHeight) { - const innerContentHeight = - containerRef.current.scrollHeight - PADDING * 2; - dispatch({ - type: SET_INITIAL_HEIGHT_VALUES, - value: innerContentHeight, - }); - } - if (rootRef.current?.clientWidth) { - const innerComponentWidth = - rootRef.current.clientWidth - MARGIN * 2 - PADDING * 2; - dispatch({ type: SET_COMPONENT_WIDTH, value: innerComponentWidth }); - } - }, []); + // useEffect(() => { + // if (containerRef.current?.scrollHeight) { + // const innerContentHeight = + // containerRef.current.scrollHeight - PADDING * 2; + // console.log('set initial height values'); + // dispatch({ + // type: SET_INITIAL_HEIGHT_VALUES, + // value: innerContentHeight, + // }); + // } + // if (rootRef.current?.clientWidth) { + // const innerComponentWidth = + // rootRef.current.clientWidth - MARGIN * 2 - PADDING * 2; + // dispatch({ type: SET_COMPONENT_WIDTH, value: innerComponentWidth }); + // } + // }, []); - useEffect(() => { - // set some values the first time when the component it's expanded - if ( - state.height === undefined && - (isUploading || isSuccess || isFailure) - ) { - if (containerRef.current?.scrollHeight) { - dispatch({ - type: SET_TOTAL_HEIGHT_PLUS, - value: containerRef.current.scrollHeight - PADDING * 2, - }); - } - if (loadingContainerRef.current?.getBoundingClientRect().top) { - dispatch({ - type: SET_POSITION_TOP_LOADING, - value: - loadingContainerRef.current.getBoundingClientRect() - .top - MARGIN, - }); - } - } - // calculate and set the width of the success and failure container component - if (isSuccess || isFailure) { - const width = containerRef.current?.getBoundingClientRect().width; - if (width) { - dispatch({ - type: SET_IS_SUCCESS_WIDTH, - value: width - PADDING * 2 - MARGIN * 2, - }); - } - } - // sets height of the component, is used to transition between heights. - if (isUploading || isSuccess || isFailure) { - if (state.totalHeightPlus) { - dispatch({ type: SET_HEIGHT, value: state.totalHeightPlus }); - } else { - dispatch({ type: SET_INITIAL_HEIGHT_PLUS_VALUES }); - } - } else if (state.totalHeight) { - dispatch({ type: SET_HEIGHT, value: state.totalHeight }); - } - // calculate and set isUploading container panel. - if ( - isUploading && - !isFailure && - !isSuccess && - loadingContainerRef.current?.scrollHeight - ) { - const loadingContainerHeight = - loadingContainerRef.current.scrollHeight; - dispatch({ - type: SET_LOADING_CONTAINER_HEIGHT, - value: loadingContainerHeight, - }); - } - }, [ - state.height, - isUploading, - isSuccess, - isFailure, - state.totalHeight, - state.totalHeightPlus, - ]); + // useEffect(() => { + // // set some values the first time when the component it's expanded + // if ( + // state.height === undefined && + // (isUploading.reduce((acc,value)=>acc||value,false) || isSuccess.reduce((acc,value)=>acc||value,false) || isFailure.reduce((acc,value)=>acc||value,false)) + // ) { + // console.log('set total height plus') + // if (containerRef.current?.scrollHeight) { + // dispatch({ + // type: SET_TOTAL_HEIGHT_PLUS, + // value: containerRef.current.scrollHeight - PADDING * 2, + // }); + // } + // if (loadingContainerRef.current?.getBoundingClientRect().top) { + // dispatch({ + // type: SET_POSITION_TOP_LOADING, + // value: + // loadingContainerRef.current.getBoundingClientRect() + // .top - MARGIN, + // }); + // } + // } + // // calculate and set the width of the success and failure container component + // if (isSuccess.reduce((acc,value)=>acc||value,false) || isFailure.reduce((acc,value)=>acc||value,false) ) { + // const width = containerRef.current?.getBoundingClientRect().width; + // if (width) { + // dispatch({ + // type: SET_IS_SUCCESS_WIDTH, + // value: width - PADDING * 2 - MARGIN * 2, + // }); + // } + // } + // // sets height of the component, is used to transition between heights. + // if (isUploading.reduce((acc,value)=>acc||value,false) || isSuccess.reduce((acc,value)=>acc||value,false) || isFailure.reduce((acc,value)=>acc||value,false) ) { + // console.log('setting totalheightplus or initial height plus values'); + // if (state.totalHeightPlus) { + // dispatch({ type: SET_HEIGHT, value: state.totalHeightPlus }); + // } else { + // dispatch({ type: SET_INITIAL_HEIGHT_PLUS_VALUES }); + // } + // } else if (state.totalHeight) { + // dispatch({ type: SET_HEIGHT, value: state.totalHeight }); + // } + // // calculate and set isUploading container panel. + // if ( + // isUploading.reduce((acc,value)=>acc||value,false) && + // !isFailure.reduce((acc,value)=>acc||value,false) && + // !isSuccess.reduce((acc,value)=>acc||value,false) && + // loadingContainerRef.current?.scrollHeight + // ) { + // console.log('setting loading container height'); + // const loadingContainerHeight = + // loadingContainerRef.current.scrollHeight; + // dispatch({ + // type: SET_LOADING_CONTAINER_HEIGHT, + // value: loadingContainerHeight, + // }); + // } + // }, [ + // state.height, + // isUploading, + // isSuccess, + // isFailure, + // state.totalHeight, + // state.totalHeightPlus, + // ]); - useEffect(() => { - if (!isUploading) { - dispatch({ type: SET_OPACITY_LOADING, value: 0 }); - } - return () => { - dispatch({ type: LOADING_RESTORE }); - }; - }, [isUploading]); + // useEffect(() => { + // isUploading.forEach((value,index)=>{ + // if(!value){ + // dispatch({ type: SET_OPACITY_LOADING, value: 0,index }); + // } + // }) + // return () => { + // isUploading.forEach((_,index)=>{ + // dispatch({ type: LOADING_RESTORE,index }); + // }) + // }; + // }, [isUploading]); - useEffect(() => { - if (!isFailure) { - dispatch({ type: SET_OPACITY_IS_FAILURE, value: 0 }); - } - return () => { - dispatch({ type: IS_FAILURE_RESTORE }); - }; - }, [isFailure]); + // useEffect(() => { + // isFailure.forEach((value,index)=>{ + // if(!value){ + // dispatch({ type: SET_OPACITY_IS_FAILURE, value: 0,index }); + // } + // }) + // return () => { + // isFailure.forEach((_,index)=>{ + // dispatch({ type: IS_FAILURE_RESTORE,index }); + // }) + // }; + // }, [isFailure]); - useEffect(() => { - if (!isSuccess) { - dispatch({ type: SET_OPACITY_IS_SUCCESS, value: 0 }); - } - return () => { - dispatch({ type: IS_SUCCESS_RESTORE }); - }; - }, [isSuccess]); + // useEffect(() => { + // isSuccess.forEach((value,index)=>{ + // if(!value){ + // dispatch({ type: SET_OPACITY_IS_SUCCESS, value: 0,index }); + // } + // }) + // return () => { + // isFailure.forEach((_,index)=>{ + // dispatch({ type: IS_SUCCESS_RESTORE,index }); + // }) + // }; + // }, [isSuccess]); // resize bottom panel width when resizing window browser - useLayoutEffect(() => { - function updateSize() { - if (rootRef.current?.clientWidth) { - const innerComponentWidth = - rootRef.current.clientWidth - MARGIN * 2 - PADDING * 2; - dispatch({ - type: SET_COMPONENT_WIDTH, - value: innerComponentWidth, - }); + // useLayoutEffect(() => { + // function updateSize() { + // if (rootRef.current?.clientWidth) { + // const innerComponentWidth = + // rootRef.current.clientWidth - MARGIN * 2 - PADDING * 2; + // dispatch({ + // type: SET_COMPONENT_WIDTH, + // value: innerComponentWidth, + // }); + // } + // if (isSuccess || isFailure) { + // const width = + // containerRef.current?.getBoundingClientRect().width; + // if (width) { + // dispatch({ + // type: SET_IS_SUCCESS_WIDTH, + // value: width - PADDING * 2 - MARGIN * 2, + // }); + // } + // } + // } + // window.addEventListener('resize', updateSize); + // updateSize(); + // return () => window.removeEventListener('resize', updateSize); + // }, [isSuccess, isFailure]); + + const renderBottomPanelContent = useCallback( + (value: IValue): React.ReactElement | undefined => { + if (value.isFailure.value) { + return ( + + ); } - if (isSuccess || isFailure) { - const width = containerRef.current?.getBoundingClientRect() - .width; - if (width) { - dispatch({ - type: SET_IS_SUCCESS_WIDTH, - value: width - PADDING * 2 - MARGIN * 2, - }); - } + if (value.isSuccess.value) { + return ( + + ); } - } - window.addEventListener('resize', updateSize); - updateSize(); - return () => window.removeEventListener('resize', updateSize); - }, [isSuccess, isFailure]); - - const renderBottomPanelContent = (): React.ReactElement | undefined => { - if (isFailure) { - return ( - - ); - } - if (isSuccess) { - return ( - - ); - } - if (isUploading) { - return ( - - ); - } - return undefined; - }; + if (value.isUploading.value) { + return ( + + ); + } + return undefined; + }, + [], + ); - const onCancelUploading = () => { - if (workerRef.current) { - workerRef.current.terminate(); - setIsUploading(false); - } + const onCancelUploading = (index: number) => () => { + workerRef.current[index].terminate(); + setInformativePanelsState((prev) => ({ + ...prev, + values: prev.values.map((value, index_) => { + if (index_ === index) + return { + ...value, + isSuccess: { ...value.isSuccess, value: false }, + isFailure: { ...value.isFailure, value: false }, + isUploading: { ...value.isUploading, value: false }, + }; + return value; + }), + index, + makeItDisappear: true, + })); }; return ( @@ -415,42 +609,51 @@ export const FileUpload: React.FC = ({ )} - - {renderBottomPanelContent()} - + {informativePanelsState.values.map((value, index) => ( + + {renderBottomPanelContent(value)} + + ))} ); }; diff --git a/src/Containers/FileUpload/reducer.ts b/src/Containers/FileUpload/reducer.ts index 1e8ae365e..15540509e 100644 --- a/src/Containers/FileUpload/reducer.ts +++ b/src/Containers/FileUpload/reducer.ts @@ -10,9 +10,9 @@ export interface IFileUploadState { totalHeight: number; totalHeightPlus: number; maxHeight: number | undefined; - loading: IOptions; - isSuccess: IOptions; - isFailure: IOptions; + loading: IOptions[]; + isSuccess: IOptions[]; + isFailure: IOptions[]; positionTopLoading: number; loadingContainerHeight: number; componentWidth: number; @@ -43,6 +43,9 @@ export const IS_FAILURE_FADE_OUT = 'IS_FAILURE_FADE_OUT'; export const IS_FAILURE_RESTORE = 'IS_FAILURE_RESTORE'; export const SET_INITIAL_HEIGHT_VALUES = 'SET_INITIAL_HEIGHT_VALUES'; export const SET_INITIAL_HEIGHT_PLUS_VALUES = 'SET_INITIAL_HEIGHT_PLUS_VALUES'; +export const ADD_LOADING_IS_SUCCESS_IS_FAILURE='ADD_LOADING_IS_SUCCESS_IS_FAILURE'; +export const RESET_LOADING_IS_SUCCESS_IS_FAILURE='RESET_LOADING_IS_SUCCESS_IS_FAILURE' +export const REMOVE_LOADING_IS_SUCCESS_IS_FAILURE='REMOVE_LOADING_IS_SUCCESS_IS_FAILURE' type Action = | { @@ -56,30 +59,46 @@ type Action = | 'SET_TOTAL_HEIGHT_PLUS' | 'SET_POSITION_TOP_LOADING' | 'SET_IS_SUCCESS_WIDTH' - | 'SET_OPACITY_LOADING' - | 'SET_OPACITY_IS_SUCCESS' - | 'SET_OPACITY_IS_FAILURE' | 'SET_LOADING_CONTAINER_HEIGHT' | 'SET_INITIAL_HEIGHT_VALUES'; value: number; } + | { + type: + | 'SET_OPACITY_LOADING' + | 'SET_OPACITY_IS_SUCCESS' + | 'SET_OPACITY_IS_FAILURE'; + value: number; + index: number; + } | { type: | 'SET_POSITION_LOADING' | 'SET_POSITION_IS_SUCCESS' - | 'SET_POSITION_IS_FAILURE' - | 'SET_IS_DRAG_ENTER'; + | 'SET_POSITION_IS_FAILURE'; + index: number; + value: boolean; + } + | { + type: 'SET_IS_DRAG_ENTER'; value: boolean; } | { type: - | 'LOADING_FADE_OUT' | 'LOADING_RESTORE' + | 'LOADING_FADE_OUT' | 'IS_SUCCESS_FADE_OUT' | 'IS_SUCCESS_RESTORE' | 'IS_FAILURE_FADE_OUT' | 'IS_FAILURE_RESTORE' - | 'SET_INITIAL_HEIGHT_PLUS_VALUES'; + |'REMOVE_LOADING_IS_SUCCESS_IS_FAILURE'; + index: number; + } + | { + type: |'SET_INITIAL_HEIGHT_PLUS_VALUES'|'RESET_LOADING_IS_SUCCESS_IS_FAILURE'; + }|{ + type:|'ADD_LOADING_IS_SUCCESS_IS_FAILURE'; + value:IOptions; }; const reducer = (state: IFileUploadState, action: Action): IFileUploadState => { @@ -122,50 +141,74 @@ const reducer = (state: IFileUploadState, action: Action): IFileUploadState => { case SET_OPACITY_LOADING: return { ...state, - loading: { - ...state.loading, - opacity: action.value, - }, + loading: state.loading.map((value, index) => { + if (index === action.index) + return { + ...state.loading[index], + opacity: action.value, + }; + return value; + }), }; case SET_POSITION_LOADING: return { ...state, - loading: { - ...state.loading, - position: action.value, - }, + loading: state.loading.map((value, index) => { + if (index === action.index) + return { + ...value, + position: action.value, + }; + return value; + }), }; case SET_OPACITY_IS_SUCCESS: return { ...state, - isSuccess: { - ...state.isSuccess, - opacity: action.value, - }, + isSuccess: state.isSuccess.map((value, index) => { + if (index === action.index) + return { + ...value, + opacity: action.value, + }; + return value; + }), }; case SET_POSITION_IS_SUCCESS: return { ...state, - isSuccess: { - ...state.isSuccess, - position: action.value, - }, + isSuccess: state.isSuccess.map((value, index) => { + if (index === action.index) + return { + ...value, + position: action.value, + }; + return value; + }), }; case SET_OPACITY_IS_FAILURE: return { ...state, - isFailure: { - ...state.isFailure, - opacity: action.value, - }, + isFailure: state.isFailure.map((value, index) => { + if (index === action.index) + return { + ...value, + opacity: action.value, + }; + return value; + }), }; case SET_POSITION_IS_FAILURE: return { ...state, - isFailure: { - ...state.isFailure, - position: action.value, - }, + isFailure: state.isFailure.map((value, index) => { + if (index === action.index) + return { + ...value, + position: action.value, + }; + return value; + }), }; case SET_LOADING_CONTAINER_HEIGHT: return { @@ -180,56 +223,80 @@ const reducer = (state: IFileUploadState, action: Action): IFileUploadState => { case LOADING_FADE_OUT: return { ...state, - loading: { - ...state.loading, - opacity: 0, - position: true, - }, + loading: state.loading.map((value, index) => { + if (index === action.index) + return { + ...value, + opacity: 0, + position: true, + }; + return value; + }), }; case LOADING_RESTORE: return { ...state, - loading: { - ...state.loading, - opacity: 1, - position: false, - }, + loading: state.loading.map((value, index) => { + if (index === action.index) + return { + ...value, + opacity: 1, + position: false, + }; + return value; + }), }; case IS_SUCCESS_FADE_OUT: return { ...state, - isSuccess: { - ...state.isSuccess, - opacity: 0, - position: true, - }, + isSuccess: state.isSuccess.map((value, index) => { + if (index === action.index) + return { + ...value, + opacity: 0, + position: true, + }; + return value; + }), }; case IS_SUCCESS_RESTORE: return { ...state, - isSuccess: { - ...state.isSuccess, - opacity: 1, - position: false, - }, + isSuccess: state.isSuccess.map((value, index) => { + if (index === action.index) + return { + ...value, + opacity: 1, + position: false, + }; + return value; + }), }; case IS_FAILURE_FADE_OUT: return { ...state, - isFailure: { - ...state.isFailure, - opacity: 0, - position: true, - }, + isFailure: state.isFailure.map((value, index) => { + if (index === action.index) + return { + ...value, + opacity: 0, + position: true, + }; + return value; + }), }; case IS_FAILURE_RESTORE: return { ...state, - isFailure: { - ...state.isFailure, - opacity: 1, - position: false, - }, + isFailure: state.isFailure.map((value, index) => { + if (index === action.index) + return { + ...value, + opacity: 1, + position: false, + }; + return value; + }), }; case SET_INITIAL_HEIGHT_VALUES: return { @@ -243,6 +310,36 @@ const reducer = (state: IFileUploadState, action: Action): IFileUploadState => { height: undefined, maxHeight: MAX_HEIGHT, }; + case ADD_LOADING_IS_SUCCESS_IS_FAILURE: + return { + ...state, + loading:[...state.loading,{position:action.value.position,opacity:action.value.opacity}], + isSuccess:[...state.isSuccess,{position:action.value.position,opacity:action.value.opacity}], + isFailure:[...state.isFailure,{position:action.value.position,opacity:action.value.opacity}] + }; + case RESET_LOADING_IS_SUCCESS_IS_FAILURE: + return{ + ...state, + loading:[], + isSuccess:[], + isFailure:[], + }; + case REMOVE_LOADING_IS_SUCCESS_IS_FAILURE: + return { + ...state, + loading:state.loading.filter((_,index)=>{ + if(index===action.index)return false + return true + }), + isSuccess:state.isSuccess.filter((_,index)=>{ + if(index===action.index)return false + return true + }), + isFailure:state.isFailure.filter((_,index)=>{ + if(index===action.index)return false + return true + }) + } default: return state; } diff --git a/src/Containers/FileUpload/worker.js b/src/Containers/FileUpload/worker.js index 7265bc1de..371076778 100644 --- a/src/Containers/FileUpload/worker.js +++ b/src/Containers/FileUpload/worker.js @@ -15,7 +15,7 @@ onmessage = (e) => { ); } } - postMessage({ base64StringFile }); + postMessage({ base64StringFile,name:file.name }); }; reader.readAsArrayBuffer(file); }; From bd833077f67ea4de180c126e11849b2b8df5001a Mon Sep 17 00:00:00 2001 From: roggc Date: Mon, 3 Jan 2022 15:49:36 +0100 Subject: [PATCH 05/20] on cancel uploading --- src/Containers/FileUpload/FileUpload.tsx | 27 ++++++++++-------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/Containers/FileUpload/FileUpload.tsx b/src/Containers/FileUpload/FileUpload.tsx index 3fde7a39e..3afcc8180 100644 --- a/src/Containers/FileUpload/FileUpload.tsx +++ b/src/Containers/FileUpload/FileUpload.tsx @@ -318,7 +318,6 @@ export const FileUpload: React.FC = ({ // make disappear a value (informative panel) useEffect(() => { if (informativePanelsState.makeItDisappear) { - // const indexToRemove = informativePanelsState.index; setInformativePanelsState((prev) => ({ ...prev, values: prev.values.filter((value) => { @@ -329,10 +328,6 @@ export const FileUpload: React.FC = ({ makeItDisappear: false, name: '', })); - // dispatch({ - // type: REMOVE_LOADING_IS_SUCCESS_IS_FAILURE, - // index: indexToRemove, - // }); } }, [informativePanelsState.makeItDisappear]); @@ -539,22 +534,22 @@ export const FileUpload: React.FC = ({ [], ); - const onCancelUploading = (index: number) => () => { - workerRef.current[index].terminate(); + const onCancelUploading = (value: IValue) => () => { + value.worker.terminate(); setInformativePanelsState((prev) => ({ ...prev, - values: prev.values.map((value, index_) => { - if (index_ === index) + values: prev.values.map((value_) => { + if (value_.name === value.name) return { - ...value, - isSuccess: { ...value.isSuccess, value: false }, - isFailure: { ...value.isFailure, value: false }, - isUploading: { ...value.isUploading, value: false }, + ...value_, + isSuccess: { ...value_.isSuccess, value: false }, + isFailure: { ...value_.isFailure, value: false }, + isUploading: { ...value_.isUploading, value: false }, }; - return value; + return value_; }), - index, makeItDisappear: true, + name:value.name, })); }; @@ -613,7 +608,7 @@ export const FileUpload: React.FC = ({ Date: Mon, 3 Jan 2022 21:21:37 +0100 Subject: [PATCH 06/20] refactor code --- src/Containers/FileUpload/FileUpload.tsx | 156 +++++++---------------- 1 file changed, 49 insertions(+), 107 deletions(-) diff --git a/src/Containers/FileUpload/FileUpload.tsx b/src/Containers/FileUpload/FileUpload.tsx index 3afcc8180..e9f2fd7db 100644 --- a/src/Containers/FileUpload/FileUpload.tsx +++ b/src/Containers/FileUpload/FileUpload.tsx @@ -56,26 +56,33 @@ const PADDING = 10; const MARGIN = 10; interface ISpecificValues { + /** value of truth for the state of the panel; example: is success is true or false */ value: boolean; + /** opacity of the panel, used for animation */ opacity: number; + /** when true panel is positioned absolute */ isPosition: boolean; } interface IValue { + /** is success state for the panel */ isSuccess: ISpecificValues; + /** is failure state for the panel */ isFailure: ISpecificValues; + /** is uploading state for the panel */ isUploading: ISpecificValues; + /** name of file */ name: string; worker: Worker; file: File; } interface IInformativePanelsState { + /** array of panels */ values: IValue[]; - /** index affected */ - index: number; - name: string; - makeItDisappear: boolean; + /** names of files already uploaded, or failed, or cancelled */ + makeItDisappear: string[]; + /** when true workers associated with the array of values (panels) will start */ startWorkers: boolean; } @@ -124,10 +131,8 @@ export const FileUpload: React.FC = ({ const [informativePanelsState, setInformativePanelsState] = useState({ values: [], - index: -1, - makeItDisappear: false, + makeItDisappear: [], startWorkers: false, - name: '', }); const initState: IFileUploadState = { height: undefined, @@ -145,8 +150,6 @@ export const FileUpload: React.FC = ({ }; const [state, dispatch] = useReducer(reducer, initState); const isMounted = useMounted(); - - const workerRef = useRef([]); /** * ref to the most outer container, which contains everything else */ @@ -169,7 +172,6 @@ export const FileUpload: React.FC = ({ setInformativePanelsState((prev) => ({ ...prev, values: [...prev.values, ...valuesToAdd], - index: -1, startWorkers: true, })); dispatch({ type: SET_IS_DRAG_ENTER, value: false }); @@ -181,12 +183,12 @@ export const FileUpload: React.FC = ({ if (base64StringFile === undefined) { return; } - if (base64StringFile === NO_BASE64STRINGFILE || isTestIsFailure) { - const value = informativePanelsState.values.find( - (value_) => value_.name === name, - ); - if (value) { - value.worker.terminate(); + const value = informativePanelsState.values.find( + (value_) => value_.name === name, + ); + if(value){ + value.worker.terminate(); + if (base64StringFile === NO_BASE64STRINGFILE || isTestIsFailure) { setInformativePanelsState((prev) => ({ ...prev, values: prev.values.map((value_) => { @@ -208,42 +210,10 @@ export const FileUpload: React.FC = ({ }; return value_; }), + makeItDisappear:[...prev.makeItDisappear,value.name] })); - setTimeout(() => { - if (isMounted.current) { - setInformativePanelsState((prev) => ({ - ...prev, - values: prev.values.map((value_) => { - if (value_.name === value.name) - return { - ...value_, - isSuccess: { - ...value_.isSuccess, - value: false, - }, - isFailure: { - ...value_.isFailure, - value: false, - }, - isUploading: { - ...value_.isUploading, - value: false, - }, - }; - return value_; - }), - makeItDisappear: true, - name: value.name, - })); - } - }, messageDuration); - } - } else { - const value = informativePanelsState.values.find( - (value_) => value_.name === name, - ); - if (value) { - value.worker.terminate(); + + } else { doWithBase64StringFile(base64StringFile); setInformativePanelsState((prev) => ({ ...prev, @@ -266,39 +236,12 @@ export const FileUpload: React.FC = ({ }; return value_; }), + makeItDisappear:[...prev.makeItDisappear,value.name] })); - setTimeout(() => { - if (isMounted.current) { - setInformativePanelsState((prev) => ({ - ...prev, - values: prev.values.map((value_) => { - if (value_.name === value.name) - return { - ...value_, - isSuccess: { - ...value_.isSuccess, - value: false, - }, - isFailure: { - ...value_.isFailure, - value: false, - }, - isUploading: { - ...value_.isUploading, - value: false, - }, - }; - return value_; - }), - makeItDisappear: true, - name: value.name, - })); - } - }, messageDuration); } } }, - [informativePanelsState.values, isTestIsFailure], + [informativePanelsState.values, isTestIsFailure,doWithBase64StringFile], ); // start workers when files have been droped @@ -315,21 +258,28 @@ export const FileUpload: React.FC = ({ } }, [informativePanelsState.startWorkers, isTestIsFailure, onWorkerMessage]); - // make disappear a value (informative panel) - useEffect(() => { - if (informativePanelsState.makeItDisappear) { - setInformativePanelsState((prev) => ({ - ...prev, - values: prev.values.filter((value) => { - if (value.name === prev.name) return false; - return true; - }), - index: -1, - makeItDisappear: false, - name: '', - })); - } - }, [informativePanelsState.makeItDisappear]); + // make disappear values (informative panels) in the future + useEffect(() => { + if(informativePanelsState.makeItDisappear.length){ + informativePanelsState.makeItDisappear.forEach(name=>{ + setTimeout(() => { + if (isMounted.current) { + setInformativePanelsState((prev) => ({ + ...prev, + values:prev.values.filter(value=>{ + if(value.name===name)return false + return true + }), + makeItDisappear: prev.makeItDisappear.filter(name_=>{ + if(name_===name)return false + return true + }), + })); + } + }, messageDuration); + }); + } + }, [informativePanelsState.makeItDisappear.length]); const onDragEnter = useCallback((event: React.DragEvent) => { event.preventDefault(); @@ -538,18 +488,10 @@ export const FileUpload: React.FC = ({ value.worker.terminate(); setInformativePanelsState((prev) => ({ ...prev, - values: prev.values.map((value_) => { - if (value_.name === value.name) - return { - ...value_, - isSuccess: { ...value_.isSuccess, value: false }, - isFailure: { ...value_.isFailure, value: false }, - isUploading: { ...value_.isUploading, value: false }, - }; - return value_; - }), - makeItDisappear: true, - name:value.name, + values:prev.values.filter(value_=>{ + if(value_.name===value.name)return false + return true + }) })); }; From 9f647e2c8a2ff6f1760b030b54f7479d4f0710d9 Mon Sep 17 00:00:00 2001 From: roggc Date: Mon, 3 Jan 2022 21:51:53 +0100 Subject: [PATCH 07/20] add story isDisabled --- src/Containers/FileUpload/FileUpload.stories.tsx | 6 ++++++ src/Containers/FileUpload/FileUpload.tsx | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Containers/FileUpload/FileUpload.stories.tsx b/src/Containers/FileUpload/FileUpload.stories.tsx index 5f0cc2cad..3059dff86 100644 --- a/src/Containers/FileUpload/FileUpload.stories.tsx +++ b/src/Containers/FileUpload/FileUpload.stories.tsx @@ -45,3 +45,9 @@ LongAnimationDuration.args = { ...Basic.args, animationDuration: 5000, }; + +export const IsDisabled = Basic.bind({}); +IsDisabled.args = { + ...Basic.args, + isDisabled: true, +}; diff --git a/src/Containers/FileUpload/FileUpload.tsx b/src/Containers/FileUpload/FileUpload.tsx index e9f2fd7db..46c58666d 100644 --- a/src/Containers/FileUpload/FileUpload.tsx +++ b/src/Containers/FileUpload/FileUpload.tsx @@ -45,6 +45,9 @@ import reducer, { REMOVE_LOADING_IS_SUCCESS_IS_FAILURE, } from './reducer'; +// TODO: Add animations if possible (height transitions of the container component (expansion-contraction)) +// and fade-in, fade-out effect of the informative panels. + const MESSAGE_DURATION = 1500; const SUCCESS_MESSAGE = 'Completed'; const FAILURE_MESSAGE = 'Something went wrong'; @@ -114,7 +117,7 @@ export interface IFileUploadProps { animationDuration?: number; } -/** multiple file upload */ +/** multiple file upload in parallel */ export const FileUpload: React.FC = ({ title = TITLE, subTitle = SUBTITLE, From 6bcf9c8a06d19678ab8ed830834e66cf9e3dbd48 Mon Sep 17 00:00:00 2001 From: roggc Date: Mon, 3 Jan 2022 23:35:28 +0100 Subject: [PATCH 08/20] some refactor - code quality --- src/Containers/FileUpload/FileUpload.tsx | 71 ++++++++++--------- .../FileUpload/IsFailureIsSuccessPanel.tsx | 2 +- src/Containers/FileUpload/reducer.ts | 15 +--- 3 files changed, 42 insertions(+), 46 deletions(-) diff --git a/src/Containers/FileUpload/FileUpload.tsx b/src/Containers/FileUpload/FileUpload.tsx index 46c58666d..8fa091179 100644 --- a/src/Containers/FileUpload/FileUpload.tsx +++ b/src/Containers/FileUpload/FileUpload.tsx @@ -21,7 +21,7 @@ import { Loading } from '../Loading/Loading'; import { BottomPanel } from './BottomPanel'; import { Container, Icon } from './StyledComponents'; import { FileMovingAnimation } from './FileMovingAnimation'; -import { IsFailureIsSuccessPanel } from './IsFailureIsSuccessPanel'; +import { IsFailureIsSuccessPanel,IIsFailureIsSuccessPanelProps } from './IsFailureIsSuccessPanel'; import { NO_BASE64STRINGFILE } from './constants'; import reducer, { IFileUploadState, @@ -74,9 +74,11 @@ interface IValue { isFailure: ISpecificValues; /** is uploading state for the panel */ isUploading: ISpecificValues; - /** name of file */ + /** name of file associated with the informative panel */ name: string; + /** worker; will do the job of reading the file */ worker: Worker; + /** the file associated with the informative panel */ file: File; } @@ -159,6 +161,9 @@ export const FileUpload: React.FC = ({ const containerRef = useRef(null); const loadingContainerRef = useRef(null); + /** + * load array of informative panels (values) and send order to start workers + */ const onDrop = useCallback((acceptedFiles: File[]) => { const valuesToAdd: IValue[] = []; acceptedFiles.forEach((file) => { @@ -180,6 +185,11 @@ export const FileUpload: React.FC = ({ dispatch({ type: SET_IS_DRAG_ENTER, value: false }); }, []); + /** + * terminate worker and set state of informative panel to success or failure and + * send order to remove informative panel in the future. also do whatever user + * wants to do with the file read in case of success + */ const onWorkerMessage = useCallback( (e: any) => { const { base64StringFile, name } = e.data; @@ -215,7 +225,6 @@ export const FileUpload: React.FC = ({ }), makeItDisappear:[...prev.makeItDisappear,value.name] })); - } else { doWithBase64StringFile(base64StringFile); setInformativePanelsState((prev) => ({ @@ -247,7 +256,8 @@ export const FileUpload: React.FC = ({ [informativePanelsState.values, isTestIsFailure,doWithBase64StringFile], ); - // start workers when files have been droped + // start workers after files have been droped and array of values (informative panels) + // are loaded useEffect(() => { if (informativePanelsState.startWorkers) { setInformativePanelsState((prev) => ({ @@ -259,7 +269,7 @@ export const FileUpload: React.FC = ({ value.worker.postMessage({ file: value.file }); }); } - }, [informativePanelsState.startWorkers, isTestIsFailure, onWorkerMessage]); + }, [informativePanelsState.startWorkers, onWorkerMessage]); // make disappear values (informative panels) in the future useEffect(() => { @@ -269,14 +279,8 @@ export const FileUpload: React.FC = ({ if (isMounted.current) { setInformativePanelsState((prev) => ({ ...prev, - values:prev.values.filter(value=>{ - if(value.name===name)return false - return true - }), - makeItDisappear: prev.makeItDisappear.filter(name_=>{ - if(name_===name)return false - return true - }), + values:prev.values.filter(value=>value.name!==name), + makeItDisappear: prev.makeItDisappear.filter(name_=>name_!==name), })); } }, messageDuration); @@ -452,27 +456,30 @@ export const FileUpload: React.FC = ({ // return () => window.removeEventListener('resize', updateSize); // }, [isSuccess, isFailure]); + /** renders isSuccess panel, or isFailure panel, or isUploading panel, depending + * on the state of the informative panel + */ const renderBottomPanelContent = useCallback( (value: IValue): React.ReactElement | undefined => { + let isFailureIsSuccessPanelProps:IIsFailureIsSuccessPanelProps|null=null if (value.isFailure.value) { - return ( - - ); + isFailureIsSuccessPanelProps={ + message:failureMessage, + iconColor:MainTheme.colors.statusColors.red, + IconToShow:TimesCircle, + transitionDuration:animationDuration + } } if (value.isSuccess.value) { - return ( - - ); + isFailureIsSuccessPanelProps={ + message:successMessage, + iconColor:MainTheme.colors.statusColors.green, + IconToShow:CheckCircle, + transitionDuration:animationDuration + } + } + if(isFailureIsSuccessPanelProps){ + return } if (value.isUploading.value) { return ( @@ -487,14 +494,12 @@ export const FileUpload: React.FC = ({ [], ); + /** cancel uploading; terminate worker and remove informative panel */ const onCancelUploading = (value: IValue) => () => { value.worker.terminate(); setInformativePanelsState((prev) => ({ ...prev, - values:prev.values.filter(value_=>{ - if(value_.name===value.name)return false - return true - }) + values:prev.values.filter(value_=>value_.name!==value.name) })); }; diff --git a/src/Containers/FileUpload/IsFailureIsSuccessPanel.tsx b/src/Containers/FileUpload/IsFailureIsSuccessPanel.tsx index b77982d86..5a1d0ff0d 100644 --- a/src/Containers/FileUpload/IsFailureIsSuccessPanel.tsx +++ b/src/Containers/FileUpload/IsFailureIsSuccessPanel.tsx @@ -3,7 +3,7 @@ import { TextLayout } from '@Layouts'; import { StyledIcon } from '@styled-icons/styled-icon'; import { Container, Icon, IContainerProps } from './StyledComponents'; -interface IIsFailureIsSuccessPanelProps extends IContainerProps{ +export interface IIsFailureIsSuccessPanelProps extends IContainerProps{ IconToShow: StyledIcon; iconColor: string; message: string; diff --git a/src/Containers/FileUpload/reducer.ts b/src/Containers/FileUpload/reducer.ts index 15540509e..d083731d1 100644 --- a/src/Containers/FileUpload/reducer.ts +++ b/src/Containers/FileUpload/reducer.ts @@ -327,18 +327,9 @@ const reducer = (state: IFileUploadState, action: Action): IFileUploadState => { case REMOVE_LOADING_IS_SUCCESS_IS_FAILURE: return { ...state, - loading:state.loading.filter((_,index)=>{ - if(index===action.index)return false - return true - }), - isSuccess:state.isSuccess.filter((_,index)=>{ - if(index===action.index)return false - return true - }), - isFailure:state.isFailure.filter((_,index)=>{ - if(index===action.index)return false - return true - }) + loading:state.loading.filter((_,index)=>index!==action.index), + isSuccess:state.isSuccess.filter((_,index)=>index!==action.index), + isFailure:state.isFailure.filter((_,index)=>index!==action.index) } default: return state; From d26c7434e16954fa1babdda35a6455c5ba32925d Mon Sep 17 00:00:00 2001 From: roggc Date: Mon, 3 Jan 2022 23:54:01 +0100 Subject: [PATCH 09/20] change the way start workers is processed --- src/Containers/FileUpload/FileUpload.tsx | 35 +++++++++++++----------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/Containers/FileUpload/FileUpload.tsx b/src/Containers/FileUpload/FileUpload.tsx index 8fa091179..efa8056db 100644 --- a/src/Containers/FileUpload/FileUpload.tsx +++ b/src/Containers/FileUpload/FileUpload.tsx @@ -87,8 +87,8 @@ interface IInformativePanelsState { values: IValue[]; /** names of files already uploaded, or failed, or cancelled */ makeItDisappear: string[]; - /** when true workers associated with the array of values (panels) will start */ - startWorkers: boolean; + /** names of files for which we want to start workers */ + startWorkers: string[]; } export interface IFileUploadProps { @@ -137,7 +137,7 @@ export const FileUpload: React.FC = ({ useState({ values: [], makeItDisappear: [], - startWorkers: false, + startWorkers: [], }); const initState: IFileUploadState = { height: undefined, @@ -165,22 +165,22 @@ export const FileUpload: React.FC = ({ * load array of informative panels (values) and send order to start workers */ const onDrop = useCallback((acceptedFiles: File[]) => { - const valuesToAdd: IValue[] = []; - acceptedFiles.forEach((file) => { + const informativePanels=acceptedFiles.map((file) => { const workerInstance = worker(); - valuesToAdd.push({ + return{ isSuccess: { value: false, isPosition: false, opacity: 1 }, isFailure: { value: false, isPosition: false, opacity: 1 }, isUploading: { value: true, isPosition: false, opacity: 1 }, name: file.name, worker: workerInstance, file, - }); + }; }); + const fileNames=acceptedFiles.map(file=>file.name) setInformativePanelsState((prev) => ({ ...prev, - values: [...prev.values, ...valuesToAdd], - startWorkers: true, + values: [...prev.values, ...informativePanels], + startWorkers: [...fileNames], })); dispatch({ type: SET_IS_DRAG_ENTER, value: false }); }, []); @@ -259,17 +259,20 @@ export const FileUpload: React.FC = ({ // start workers after files have been droped and array of values (informative panels) // are loaded useEffect(() => { - if (informativePanelsState.startWorkers) { + if (informativePanelsState.startWorkers.length) { + informativePanelsState.startWorkers.forEach(name=>{ + const informativePanel= informativePanelsState.values.find(value=>value.name===name); + if(informativePanel){ + informativePanel.worker.onmessage=onWorkerMessage; + informativePanel.worker.postMessage({file:informativePanel.file}); + } + }); setInformativePanelsState((prev) => ({ ...prev, - startWorkers: false, + startWorkers: [], })); - informativePanelsState.values.forEach((value) => { - value.worker.onmessage = onWorkerMessage; - value.worker.postMessage({ file: value.file }); - }); } - }, [informativePanelsState.startWorkers, onWorkerMessage]); + }, [informativePanelsState.startWorkers.length, onWorkerMessage]); // make disappear values (informative panels) in the future useEffect(() => { From c8c58a6512aaf9531343ecf26b66dc78cc2c4eb4 Mon Sep 17 00:00:00 2001 From: roggc Date: Tue, 4 Jan 2022 00:07:09 +0100 Subject: [PATCH 10/20] code quality- variable names --- src/Containers/FileUpload/FileUpload.tsx | 145 ++++++++++++++--------- 1 file changed, 88 insertions(+), 57 deletions(-) diff --git a/src/Containers/FileUpload/FileUpload.tsx b/src/Containers/FileUpload/FileUpload.tsx index efa8056db..4bde7e726 100644 --- a/src/Containers/FileUpload/FileUpload.tsx +++ b/src/Containers/FileUpload/FileUpload.tsx @@ -21,7 +21,10 @@ import { Loading } from '../Loading/Loading'; import { BottomPanel } from './BottomPanel'; import { Container, Icon } from './StyledComponents'; import { FileMovingAnimation } from './FileMovingAnimation'; -import { IsFailureIsSuccessPanel,IIsFailureIsSuccessPanelProps } from './IsFailureIsSuccessPanel'; +import { + IsFailureIsSuccessPanel, + IIsFailureIsSuccessPanelProps, +} from './IsFailureIsSuccessPanel'; import { NO_BASE64STRINGFILE } from './constants'; import reducer, { IFileUploadState, @@ -165,9 +168,9 @@ export const FileUpload: React.FC = ({ * load array of informative panels (values) and send order to start workers */ const onDrop = useCallback((acceptedFiles: File[]) => { - const informativePanels=acceptedFiles.map((file) => { + const informativePanels = acceptedFiles.map((file) => { const workerInstance = worker(); - return{ + return { isSuccess: { value: false, isPosition: false, opacity: 1 }, isFailure: { value: false, isPosition: false, opacity: 1 }, isUploading: { value: true, isPosition: false, opacity: 1 }, @@ -176,7 +179,7 @@ export const FileUpload: React.FC = ({ file, }; }); - const fileNames=acceptedFiles.map(file=>file.name) + const fileNames = acceptedFiles.map((file) => file.name); setInformativePanelsState((prev) => ({ ...prev, values: [...prev.values, ...informativePanels], @@ -186,8 +189,8 @@ export const FileUpload: React.FC = ({ }, []); /** - * terminate worker and set state of informative panel to success or failure and - * send order to remove informative panel in the future. also do whatever user + * terminate worker and set state of informative panel to success or failure and + * send order to remove informative panel in the future. also do whatever user * wants to do with the file read in case of success */ const onWorkerMessage = useCallback( @@ -196,75 +199,92 @@ export const FileUpload: React.FC = ({ if (base64StringFile === undefined) { return; } - const value = informativePanelsState.values.find( - (value_) => value_.name === name, + const informativePanel = informativePanelsState.values.find( + (value) => value.name === name, ); - if(value){ - value.worker.terminate(); - if (base64StringFile === NO_BASE64STRINGFILE || isTestIsFailure) { + if (informativePanel) { + informativePanel.worker.terminate(); + if ( + base64StringFile === NO_BASE64STRINGFILE || + isTestIsFailure + ) { setInformativePanelsState((prev) => ({ ...prev, - values: prev.values.map((value_) => { - if (value_.name === value.name) + values: prev.values.map((value) => { + if (value.name === informativePanel.name) return { - ...value_, + ...value, isSuccess: { - ...value_.isSuccess, + ...value.isSuccess, value: false, }, isFailure: { - ...value_.isFailure, + ...value.isFailure, value: true, }, isUploading: { - ...value_.isUploading, + ...value.isUploading, value: false, }, }; - return value_; + return value; }), - makeItDisappear:[...prev.makeItDisappear,value.name] + makeItDisappear: [ + ...prev.makeItDisappear, + informativePanel.name, + ], })); } else { doWithBase64StringFile(base64StringFile); setInformativePanelsState((prev) => ({ ...prev, - values: prev.values.map((value_) => { - if (value_.name === value.name) + values: prev.values.map((value) => { + if (value.name === informativePanel.name) return { - ...value_, + ...value, isSuccess: { - ...value_.isSuccess, + ...value.isSuccess, value: true, }, isFailure: { - ...value_.isFailure, + ...value.isFailure, value: false, }, isUploading: { - ...value_.isUploading, + ...value.isUploading, value: false, }, }; - return value_; + return value; }), - makeItDisappear:[...prev.makeItDisappear,value.name] + makeItDisappear: [ + ...prev.makeItDisappear, + informativePanel.name, + ], })); } } }, - [informativePanelsState.values, isTestIsFailure,doWithBase64StringFile], + [ + informativePanelsState.values, + isTestIsFailure, + doWithBase64StringFile, + ], ); // start workers after files have been droped and array of values (informative panels) // are loaded useEffect(() => { if (informativePanelsState.startWorkers.length) { - informativePanelsState.startWorkers.forEach(name=>{ - const informativePanel= informativePanelsState.values.find(value=>value.name===name); - if(informativePanel){ - informativePanel.worker.onmessage=onWorkerMessage; - informativePanel.worker.postMessage({file:informativePanel.file}); + informativePanelsState.startWorkers.forEach((name) => { + const informativePanel = informativePanelsState.values.find( + (value) => value.name === name, + ); + if (informativePanel) { + informativePanel.worker.onmessage = onWorkerMessage; + informativePanel.worker.postMessage({ + file: informativePanel.file, + }); } }); setInformativePanelsState((prev) => ({ @@ -275,20 +295,24 @@ export const FileUpload: React.FC = ({ }, [informativePanelsState.startWorkers.length, onWorkerMessage]); // make disappear values (informative panels) in the future - useEffect(() => { - if(informativePanelsState.makeItDisappear.length){ - informativePanelsState.makeItDisappear.forEach(name=>{ + useEffect(() => { + if (informativePanelsState.makeItDisappear.length) { + informativePanelsState.makeItDisappear.forEach((name) => { setTimeout(() => { if (isMounted.current) { setInformativePanelsState((prev) => ({ ...prev, - values:prev.values.filter(value=>value.name!==name), - makeItDisappear: prev.makeItDisappear.filter(name_=>name_!==name), + values: prev.values.filter( + (value) => value.name !== name, + ), + makeItDisappear: prev.makeItDisappear.filter( + (name_) => name_ !== name, + ), })); } }, messageDuration); }); - } + } }, [informativePanelsState.makeItDisappear.length]); const onDragEnter = useCallback((event: React.DragEvent) => { @@ -464,25 +488,30 @@ export const FileUpload: React.FC = ({ */ const renderBottomPanelContent = useCallback( (value: IValue): React.ReactElement | undefined => { - let isFailureIsSuccessPanelProps:IIsFailureIsSuccessPanelProps|null=null + let isFailureIsSuccessPanelProps: IIsFailureIsSuccessPanelProps | null = + null; if (value.isFailure.value) { - isFailureIsSuccessPanelProps={ - message:failureMessage, - iconColor:MainTheme.colors.statusColors.red, - IconToShow:TimesCircle, - transitionDuration:animationDuration - } + isFailureIsSuccessPanelProps = { + message: failureMessage, + iconColor: MainTheme.colors.statusColors.red, + IconToShow: TimesCircle, + transitionDuration: animationDuration, + }; } if (value.isSuccess.value) { - isFailureIsSuccessPanelProps={ - message:successMessage, - iconColor:MainTheme.colors.statusColors.green, - IconToShow:CheckCircle, - transitionDuration:animationDuration - } + isFailureIsSuccessPanelProps = { + message: successMessage, + iconColor: MainTheme.colors.statusColors.green, + IconToShow: CheckCircle, + transitionDuration: animationDuration, + }; } - if(isFailureIsSuccessPanelProps){ - return + if (isFailureIsSuccessPanelProps) { + return ( + + ); } if (value.isUploading.value) { return ( @@ -498,11 +527,13 @@ export const FileUpload: React.FC = ({ ); /** cancel uploading; terminate worker and remove informative panel */ - const onCancelUploading = (value: IValue) => () => { - value.worker.terminate(); + const onCancelUploading = (informativePanel: IValue) => () => { + informativePanel.worker.terminate(); setInformativePanelsState((prev) => ({ ...prev, - values:prev.values.filter(value_=>value_.name!==value.name) + values: prev.values.filter( + (value) => value.name !== informativePanel.name, + ), })); }; From c1fab0d07e524dcf7825830714ba2b1190f38a64 Mon Sep 17 00:00:00 2001 From: roggc Date: Sat, 8 Jan 2022 10:15:29 +0100 Subject: [PATCH 11/20] modify when workers are terminated --- src/Containers/FileUpload/FileUpload.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Containers/FileUpload/FileUpload.tsx b/src/Containers/FileUpload/FileUpload.tsx index 4bde7e726..91f276fbc 100644 --- a/src/Containers/FileUpload/FileUpload.tsx +++ b/src/Containers/FileUpload/FileUpload.tsx @@ -203,7 +203,6 @@ export const FileUpload: React.FC = ({ (value) => value.name === name, ); if (informativePanel) { - informativePanel.worker.terminate(); if ( base64StringFile === NO_BASE64STRINGFILE || isTestIsFailure @@ -303,7 +302,13 @@ export const FileUpload: React.FC = ({ setInformativePanelsState((prev) => ({ ...prev, values: prev.values.filter( - (value) => value.name !== name, + (value) => { + if(value.name===name){ + value.worker.terminate(); + return false + } + return true + }, ), makeItDisappear: prev.makeItDisappear.filter( (name_) => name_ !== name, From 6d36cb21d0f536478f24ed4e359af37d2d28d22a Mon Sep 17 00:00:00 2001 From: roggc Date: Sat, 8 Jan 2022 16:45:36 +0100 Subject: [PATCH 12/20] modify how workers are terminated when uploading is cancelled --- src/Containers/FileUpload/FileUpload.tsx | 27 ++++++++++++------------ 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/Containers/FileUpload/FileUpload.tsx b/src/Containers/FileUpload/FileUpload.tsx index 91f276fbc..79921064c 100644 --- a/src/Containers/FileUpload/FileUpload.tsx +++ b/src/Containers/FileUpload/FileUpload.tsx @@ -301,15 +301,13 @@ export const FileUpload: React.FC = ({ if (isMounted.current) { setInformativePanelsState((prev) => ({ ...prev, - values: prev.values.filter( - (value) => { - if(value.name===name){ - value.worker.terminate(); - return false - } - return true - }, - ), + values: prev.values.filter((value) => { + if (value.name === name) { + value.worker.terminate(); + return false; + } + return true; + }), makeItDisappear: prev.makeItDisappear.filter( (name_) => name_ !== name, ), @@ -533,12 +531,15 @@ export const FileUpload: React.FC = ({ /** cancel uploading; terminate worker and remove informative panel */ const onCancelUploading = (informativePanel: IValue) => () => { - informativePanel.worker.terminate(); setInformativePanelsState((prev) => ({ ...prev, - values: prev.values.filter( - (value) => value.name !== informativePanel.name, - ), + values: prev.values.filter((value) => { + if (value.name === informativePanel.name) { + value.worker.terminate(); + return false; + } + return true; + }), })); }; From 76faad7a55d5265227765e68939a005b2c1f525d Mon Sep 17 00:00:00 2001 From: roggc Date: Sat, 8 Jan 2022 18:03:01 +0100 Subject: [PATCH 13/20] modify names of properties animationDuration and transitionDuration --- src/Containers/FileUpload/FileUpload.tsx | 14 +++++++------- src/Containers/FileUpload/StyledComponents.ts | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Containers/FileUpload/FileUpload.tsx b/src/Containers/FileUpload/FileUpload.tsx index 79921064c..6d697765d 100644 --- a/src/Containers/FileUpload/FileUpload.tsx +++ b/src/Containers/FileUpload/FileUpload.tsx @@ -119,7 +119,7 @@ export interface IFileUploadProps { /** if true, failure message will appear even after success operation; its purpose is to test the appearance of the failure message during development */ isTestIsFailure?: boolean; /** height and fade in-fade out animation duration in ms; default value: 200 */ - animationDuration?: number; + heightAndOpacityTransitionDuration?: number; } /** multiple file upload in parallel */ @@ -134,7 +134,7 @@ export const FileUpload: React.FC = ({ isDisabled = false, messageDuration = MESSAGE_DURATION, isTestIsFailure, - animationDuration = TRANSITION_HEIGHT_ANIMATION_DURATION, + heightAndOpacityTransitionDuration = TRANSITION_HEIGHT_ANIMATION_DURATION, }): React.ReactElement => { const [informativePanelsState, setInformativePanelsState] = useState({ @@ -498,7 +498,7 @@ export const FileUpload: React.FC = ({ message: failureMessage, iconColor: MainTheme.colors.statusColors.red, IconToShow: TimesCircle, - transitionDuration: animationDuration, + heightAndOpacityTransitionDuration, }; } if (value.isSuccess.value) { @@ -506,7 +506,7 @@ export const FileUpload: React.FC = ({ message: successMessage, iconColor: MainTheme.colors.statusColors.green, IconToShow: CheckCircle, - transitionDuration: animationDuration, + heightAndOpacityTransitionDuration, }; } if (isFailureIsSuccessPanelProps) { @@ -554,7 +554,7 @@ export const FileUpload: React.FC = ({ height={state.height} margin={`${MARGIN}px`} isWidthFitContent - transitionDuration={animationDuration} + heightAndOpacityTransitionDuration={heightAndOpacityTransitionDuration} > {() => ( @@ -567,7 +567,7 @@ export const FileUpload: React.FC = ({ padding: '10px', margin: `${MARGIN}px`, })} - transitionDuration={animationDuration} + heightAndOpacityTransitionDuration={heightAndOpacityTransitionDuration} > = ({ ? true : undefined } - transitionDuration={animationDuration} + heightAndOpacityTransitionDuration={heightAndOpacityTransitionDuration} > {renderBottomPanelContent(value)} diff --git a/src/Containers/FileUpload/StyledComponents.ts b/src/Containers/FileUpload/StyledComponents.ts index f5263c84a..e7e2b9879 100644 --- a/src/Containers/FileUpload/StyledComponents.ts +++ b/src/Containers/FileUpload/StyledComponents.ts @@ -21,7 +21,7 @@ export interface IContainerProps { positionTop?: number; flexGrow?: boolean; /** transition duration in ms; applied on height and opacity properties; */ - transitionDuration:number; + heightAndOpacityTransitionDuration:number; } export const Container = styled.div` @@ -44,7 +44,7 @@ export const Container = styled.div` margin, positionTop, flexGrow, - transitionDuration, + heightAndOpacityTransitionDuration, }): string => ` ${borderRadius ? `border-radius:${borderRadius};` : 'border-radius:10px;'} ${ @@ -88,7 +88,7 @@ ${position ? `position:absolute;top:${positionTop}px;` : ''} ${margin ? `margin:${margin};` : ''} ${flexGrow ? `flex:1;` : ''} -transition:height ${transitionDuration}ms,opacity ${transitionDuration}ms,max-height ${transitionDuration*10}ms; +transition:height ${heightAndOpacityTransitionDuration}ms,opacity ${heightAndOpacityTransitionDuration}ms,max-height ${heightAndOpacityTransitionDuration*10}ms; `} `; From a212b7e24c74b23833430539f286a7b6c99fbce7 Mon Sep 17 00:00:00 2001 From: roggc Date: Sun, 9 Jan 2022 00:09:47 +0100 Subject: [PATCH 14/20] delete story about animation duration --- src/Containers/FileUpload/FileUpload.stories.tsx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Containers/FileUpload/FileUpload.stories.tsx b/src/Containers/FileUpload/FileUpload.stories.tsx index 3059dff86..3c3875f13 100644 --- a/src/Containers/FileUpload/FileUpload.stories.tsx +++ b/src/Containers/FileUpload/FileUpload.stories.tsx @@ -40,12 +40,6 @@ TestIsFailureTrue.args = { isTestIsFailure: true, }; -export const LongAnimationDuration = Basic.bind({}); -LongAnimationDuration.args = { - ...Basic.args, - animationDuration: 5000, -}; - export const IsDisabled = Basic.bind({}); IsDisabled.args = { ...Basic.args, From 3a71c975cef9b7cc76dfd0fae007497d933d89c5 Mon Sep 17 00:00:00 2001 From: roggc Date: Wed, 12 Jan 2022 09:07:29 +0100 Subject: [PATCH 15/20] fileuploadv2 --- src/Containers/FileUploadV2/DropArea.tsx | 42 +++ .../FileUploadV2/FileUploadV2.stories.tsx | 22 ++ src/Containers/FileUploadV2/FileUploadV2.tsx | 268 ++++++++++++++++++ src/Containers/FileUploadV2/Panel.tsx | 35 +++ src/Containers/FileUploadV2/worker.ts | 26 ++ src/Containers/index.ts | 1 + src/Inputs/CustomSearch/CustomSearch.tsx | 2 +- 7 files changed, 395 insertions(+), 1 deletion(-) create mode 100644 src/Containers/FileUploadV2/DropArea.tsx create mode 100644 src/Containers/FileUploadV2/FileUploadV2.stories.tsx create mode 100644 src/Containers/FileUploadV2/FileUploadV2.tsx create mode 100644 src/Containers/FileUploadV2/Panel.tsx create mode 100644 src/Containers/FileUploadV2/worker.ts diff --git a/src/Containers/FileUploadV2/DropArea.tsx b/src/Containers/FileUploadV2/DropArea.tsx new file mode 100644 index 000000000..8b8fa47a5 --- /dev/null +++ b/src/Containers/FileUploadV2/DropArea.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import styled from 'styled-components'; +import {IDropAreaProps} from './FileUploadV2'; + +const DropArea: React.FC = ({ + isDragEnter, + ...props +}) => ( + + Drag and drop your files here or click to select + +); + +export default DropArea + +const DropAreaContainer = styled.div` + border: 2px dashed grey; + border-radius: 10px; + padding: 10px; + ${({ isDragEnter }): string => ` + ${ + isDragEnter + ? ` + background-color:#cce6ff; + @keyframes border-dance { + 0% { + background-position: left top, right bottom, left bottom, right top; + } + 100% { + background-position: left 15px top, right 15px bottom , left bottom 15px , right top 15px; + } + } + background-image: linear-gradient(90deg, #3399ff 50%, transparent 50%), linear-gradient(90deg, #3399ff 50%, transparent 50%), linear-gradient(0deg, #3399ff 50%, transparent 50%), linear-gradient(0deg, #3399ff 50%, transparent 50%); + background-repeat: repeat-x, repeat-x, repeat-y, repeat-y; + background-size: 15px 2px, 15px 2px, 2px 15px, 2px 15px; + background-position: left top, right bottom, left bottom, right top; + animation: border-dance .3s infinite linear; + ` + : '' +} + `} +`; \ No newline at end of file diff --git a/src/Containers/FileUploadV2/FileUploadV2.stories.tsx b/src/Containers/FileUploadV2/FileUploadV2.stories.tsx new file mode 100644 index 000000000..ac852fc0e --- /dev/null +++ b/src/Containers/FileUploadV2/FileUploadV2.stories.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { Meta, Story } from '@storybook/react'; +import { FileUploadV2, IFileUploadV2Props } from '../../index'; +import DropArea from './DropArea'; + + +export default { + title: 'Components/FileUploadV2', + component: FileUploadV2, + args: { + DropArea, + }, +} as Meta; + +export const Basic: Story = (args) => ( + +); + +export const Basic2 = Basic.bind({}); +Basic2.args = { + ...Basic.args, +}; diff --git a/src/Containers/FileUploadV2/FileUploadV2.tsx b/src/Containers/FileUploadV2/FileUploadV2.tsx new file mode 100644 index 000000000..d0fc8c684 --- /dev/null +++ b/src/Containers/FileUploadV2/FileUploadV2.tsx @@ -0,0 +1,268 @@ +import React, { useState, useCallback, useEffect } from 'react'; +import styled from 'styled-components'; +// @ts-ignore +import worker from 'workerize-loader!./worker'; // eslint-disable-line +import { useMounted } from '@Utils/Hooks'; +import Dropzone, { useDropzone } from 'react-dropzone'; +import Panel,{OperationState} from './Panel'; + +// TODO: Add animations if possible (height transitions of the container component (expansion-contraction)) +// and fade-in, fade-out effect of the informative panels. + +const MESSAGE_DURATION = 1500; +const NO_BASE64STRINGFILE = 'NO_BASE64STRINGFILE'; + +interface IPanel { + /** is success state for the panel */ + isSuccess: boolean; + /** is failure state for the panel */ + isFailure: boolean; + /** is uploading state for the panel */ + isUploading: boolean; + /** name of file associated with the informative panel */ + name: string; + /** worker; will do the job of reading the file */ + worker: Worker; + /** the file associated with the informative panel */ + file: File; +} + +interface IInformativePanels { + /** array of panels */ + panels: IPanel[]; + /** names of files already uploaded, or failed, or cancelled */ + makeItDisappear: string[]; + /** names of files for which we want to start workers */ + startWorkers: string[]; +} + +export interface IDropAreaProps extends React.HTMLAttributes { + isDragEnter?: boolean; +} + +export interface IFileUploadV2Props + extends React.HTMLAttributes { + /** whether or not the file upload component is disabled */ + isDisabled?: boolean; + /** component to render the drop area */ + DropArea: React.FC; + /** if true, failure message will appear even after success operation; its purpose is to test the appearance of the failure message during development */ + isTestIsFailure?: boolean; + /** + * function to process the file read and transformed to a base64 string; default: does nothing + * @param {string} base64String the file read and transformed to a base64 string + */ + processFile?: (base64String: string) => void; + /** time in ms of the presence of the bottom panel informing the result of the operation (sucess or failure); default value: 1500 */ + messageDuration?: number; +} +/** + * multiple file upload, in parallel, version 2 + */ +export const FileUploadV2: React.FC = ({ + isDisabled = false, + DropArea, + isTestIsFailure = false, + processFile = (base64String: string) => null, + messageDuration = MESSAGE_DURATION, + ...props +}): React.ReactElement => { + const isMounted = useMounted(); + const [informativePanels, setInformativePanels] = + useState({ + panels: [], + makeItDisappear: [], + startWorkers: [], + }); + const [isDragEnter, setIsDragEnter] = useState(false); + + /** + * terminate worker and set state of informative panel to success or failure and + * send order to remove informative panel in the future. also do whatever user + * wants to do with the file read in case of success + */ + const onWorkerMessage = useCallback( + (e: any) => { + const { base64StringFile, name } = e.data; + if (base64StringFile === undefined) { + return; + } + console.log('file name', name); + console.log('informativePanels', informativePanels.panels); + const informativePanel = informativePanels.panels.find( + (panel) => panel.name === name, + ); + console.log('informativePanel', informativePanel); + if (informativePanel) { + if ( + base64StringFile === NO_BASE64STRINGFILE || + isTestIsFailure + ) { + setInformativePanels((prev) => ({ + ...prev, + panels: prev.panels.map((panel) => { + if (panel.name === informativePanel.name) + return { + ...panel, + isSuccess: false, + isFailure: true, + isUploading: false, + }; + return panel; + }), + makeItDisappear: [ + ...prev.makeItDisappear, + informativePanel.name, + ], + })); + } else { + console.log('processing file'); + processFile(base64StringFile); + setInformativePanels((prev) => ({ + ...prev, + panels: prev.panels.map((panel) => { + if (panel.name === informativePanel.name) + return { + ...panel, + isSuccess: true, + isFailure: false, + isUploading: false, + }; + return panel; + }), + makeItDisappear: [ + ...prev.makeItDisappear, + informativePanel.name, + ], + })); + } + } + }, + [informativePanels.panels, isTestIsFailure, processFile], + ); + + const onDragEnter = () => { + setIsDragEnter(true); + }; + + const onDragLeave = () => { + setIsDragEnter(false); + }; + + /** + * load array of informative panels and send order to start workers + */ + const onDrop = useCallback((acceptedFiles: File[]) => { + console.log('dropped'); + const newInformativePanels = acceptedFiles.map((file) => { + const workerInstance = worker(); + return { + isSuccess: false, + isFailure: false, + isUploading: true, + name: file.name, + worker: workerInstance, + file, + }; + }); + const fileNames = acceptedFiles.map((file) => file.name); + console.log('newInformativePanels', newInformativePanels); + setInformativePanels((prev) => ({ + ...prev, + panels: [...prev.panels, ...newInformativePanels], + startWorkers: [...fileNames], + })); + setIsDragEnter(false); + }, []); + + // start workers after files have been droped and array of informative panels + // are loaded + useEffect(() => { + if (informativePanels.startWorkers.length) { + console.log('useEffect', informativePanels.startWorkers); + informativePanels.startWorkers.forEach((name) => { + const informativePanel = informativePanels.panels.find( + (panel) => panel.name === name, + ); + if (informativePanel) { + informativePanel.worker.onmessage = onWorkerMessage; + informativePanel.worker.postMessage({ + file: informativePanel.file, + }); + } + }); + setInformativePanels((prev) => ({ + ...prev, + startWorkers: [], + })); + } + }, [informativePanels.startWorkers.length]); + + // make disappear informative panels in the future + useEffect(() => { + if (informativePanels.makeItDisappear.length) { + informativePanels.makeItDisappear.forEach((name) => { + setTimeout(() => { + if (isMounted.current) { + setInformativePanels((prev) => ({ + ...prev, + panels: prev.panels.filter((panel) => { + if (panel.name === name) { + panel.worker.terminate(); + return false; + } + return true; + }), + makeItDisappear: prev.makeItDisappear.filter( + (name_) => name_ !== name, + ), + })); + } + }, messageDuration); + }); + } + }, [informativePanels.makeItDisappear.length]); + + const { getRootProps, getInputProps } = useDropzone({ + onDrop, + onDragEnter, + onDragLeave, + disabled: isDisabled, + }); + + const getOperationState=(panel:IPanel):OperationState=>{ + if(panel.isFailure){ + return OperationState.isFailure; + } + if(panel.isSuccess){ + return OperationState.isSuccess; + } + if(panel.isUploading){ + return OperationState.isLoading; + } + return OperationState.isUnknown; + } + + return ( + + + {() => ( +
+ + +
+ )} +
+ {informativePanels.panels.map((panel) => ( + + ))} +
+ ); +}; + +const FileUploadV2Container = styled.div` + background-color: white; + border-radius: 10px; + padding: 10px; + width: fit-content; +`; diff --git a/src/Containers/FileUploadV2/Panel.tsx b/src/Containers/FileUploadV2/Panel.tsx new file mode 100644 index 000000000..622ed0c6e --- /dev/null +++ b/src/Containers/FileUploadV2/Panel.tsx @@ -0,0 +1,35 @@ +import React, { useCallback } from 'react'; +import styled from 'styled-components'; + +export enum OperationState { + isSuccess, + isFailure, + isLoading, + isUnknown +} + +interface IPanelProps extends React.HTMLAttributes { + operationState?: OperationState; + /** the name of the file */ + name?: string; +} + +const Panel: React.FC = ({ operationState=OperationState.isUnknown, name='', ...props }) => { + const getMessage = useCallback((): string => { + switch (operationState) { + case OperationState.isFailure: + return 'something went wrong'; + case OperationState.isSuccess: + return 'completed'; + case OperationState.isLoading: + return `loading ${name} ...`; + default: + return ''; + } + }, [name, operationState]); + return {getMessage()}; +}; + +export default Panel; + +const PanelContainer = styled.div``; diff --git a/src/Containers/FileUploadV2/worker.ts b/src/Containers/FileUploadV2/worker.ts new file mode 100644 index 000000000..4b75576fd --- /dev/null +++ b/src/Containers/FileUploadV2/worker.ts @@ -0,0 +1,26 @@ +onmessage = (e) => { + const { file } = e.data; + console.log('onworker',e); + const reader = new FileReader(); + reader.onload = () => { + let base64StringFile = 'NO_BASE64STRINGFILE'; + if (reader.result) { + if (typeof reader.result === 'string') { + base64StringFile = btoa(reader.result); + } else { + const bytes = Array.from(new Uint8Array(reader.result)); + base64StringFile = btoa( + bytes.map((item) => String.fromCharCode(item)).join(''), + ); + } + } + console.log('worker;post-message'); + postMessage({ base64StringFile,name:file.name }); + }; + try{ + reader.readAsArrayBuffer(file); + }catch(error){ + console.log(error); + postMessage({}); + } +}; \ No newline at end of file diff --git a/src/Containers/index.ts b/src/Containers/index.ts index 15a9ea2dd..c7c081752 100644 --- a/src/Containers/index.ts +++ b/src/Containers/index.ts @@ -97,3 +97,4 @@ export * from './ReachIndicator/ReachIndicator'; export * from './InfoHeader/InfoHeader'; export * from './StoreSelector/StoreSelector'; export * from './ScreenFlashEffect/ScreenFlashEffect'; +export * from './FileUploadV2/FileUploadV2'; diff --git a/src/Inputs/CustomSearch/CustomSearch.tsx b/src/Inputs/CustomSearch/CustomSearch.tsx index d8bdc21d5..491cc3d66 100644 --- a/src/Inputs/CustomSearch/CustomSearch.tsx +++ b/src/Inputs/CustomSearch/CustomSearch.tsx @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import styled from 'styled-components'; import { StyledIcon } from 'styled-icons/types'; import { MainInterface, ResponsiveInterface } from '@Utils/BaseStyles'; -import { Card as C } from '../../Containers'; +import { Card as C } from '@Containers'; import { Button as B } from '../Button/Button'; import { Select } from '../Select/Select'; import { SearchBar } from '../SearchBar/SearchBar'; From cfc3d09a6af114fd8444a9594d41283ab2f913ac Mon Sep 17 00:00:00 2001 From: roggc Date: Wed, 12 Jan 2022 09:22:35 +0100 Subject: [PATCH 16/20] operationState --- .../FileUploadV2/FileUploadV2.stories.tsx | 6 ++- src/Containers/FileUploadV2/FileUploadV2.tsx | 44 ++++++------------- src/Containers/FileUploadV2/Panel.tsx | 2 +- 3 files changed, 19 insertions(+), 33 deletions(-) diff --git a/src/Containers/FileUploadV2/FileUploadV2.stories.tsx b/src/Containers/FileUploadV2/FileUploadV2.stories.tsx index ac852fc0e..2f0658415 100644 --- a/src/Containers/FileUploadV2/FileUploadV2.stories.tsx +++ b/src/Containers/FileUploadV2/FileUploadV2.stories.tsx @@ -9,6 +9,7 @@ export default { component: FileUploadV2, args: { DropArea, + processFile:(base64StringFile:string)=>{console.log(base64StringFile)} }, } as Meta; @@ -16,7 +17,8 @@ export const Basic: Story = (args) => ( ); -export const Basic2 = Basic.bind({}); -Basic2.args = { +export const TestIsFailure = Basic.bind({}); +TestIsFailure.args = { ...Basic.args, + isTestIsFailure:true }; diff --git a/src/Containers/FileUploadV2/FileUploadV2.tsx b/src/Containers/FileUploadV2/FileUploadV2.tsx index d0fc8c684..da27fc630 100644 --- a/src/Containers/FileUploadV2/FileUploadV2.tsx +++ b/src/Containers/FileUploadV2/FileUploadV2.tsx @@ -4,7 +4,7 @@ import styled from 'styled-components'; import worker from 'workerize-loader!./worker'; // eslint-disable-line import { useMounted } from '@Utils/Hooks'; import Dropzone, { useDropzone } from 'react-dropzone'; -import Panel,{OperationState} from './Panel'; +import Panel from './Panel'; // TODO: Add animations if possible (height transitions of the container component (expansion-contraction)) // and fade-in, fade-out effect of the informative panels. @@ -12,13 +12,16 @@ import Panel,{OperationState} from './Panel'; const MESSAGE_DURATION = 1500; const NO_BASE64STRINGFILE = 'NO_BASE64STRINGFILE'; +enum OperationState { + isSuccess, + isFailure, + isLoading, + isUnknown +} + interface IPanel { - /** is success state for the panel */ - isSuccess: boolean; - /** is failure state for the panel */ - isFailure: boolean; - /** is uploading state for the panel */ - isUploading: boolean; + /** whether it's loading file, is completed, is failure */ + operationState:OperationState; /** name of file associated with the informative panel */ name: string; /** worker; will do the job of reading the file */ @@ -104,9 +107,7 @@ export const FileUploadV2: React.FC = ({ if (panel.name === informativePanel.name) return { ...panel, - isSuccess: false, - isFailure: true, - isUploading: false, + operationState:OperationState.isFailure }; return panel; }), @@ -124,9 +125,7 @@ export const FileUploadV2: React.FC = ({ if (panel.name === informativePanel.name) return { ...panel, - isSuccess: true, - isFailure: false, - isUploading: false, + operationState:OperationState.isSuccess }; return panel; }), @@ -157,9 +156,7 @@ export const FileUploadV2: React.FC = ({ const newInformativePanels = acceptedFiles.map((file) => { const workerInstance = worker(); return { - isSuccess: false, - isFailure: false, - isUploading: true, + operationState:OperationState.isLoading, name: file.name, worker: workerInstance, file, @@ -230,19 +227,6 @@ export const FileUploadV2: React.FC = ({ disabled: isDisabled, }); - const getOperationState=(panel:IPanel):OperationState=>{ - if(panel.isFailure){ - return OperationState.isFailure; - } - if(panel.isSuccess){ - return OperationState.isSuccess; - } - if(panel.isUploading){ - return OperationState.isLoading; - } - return OperationState.isUnknown; - } - return ( @@ -254,7 +238,7 @@ export const FileUploadV2: React.FC = ({ )} {informativePanels.panels.map((panel) => ( - + ))} ); diff --git a/src/Containers/FileUploadV2/Panel.tsx b/src/Containers/FileUploadV2/Panel.tsx index 622ed0c6e..2d0a4cc84 100644 --- a/src/Containers/FileUploadV2/Panel.tsx +++ b/src/Containers/FileUploadV2/Panel.tsx @@ -1,7 +1,7 @@ import React, { useCallback } from 'react'; import styled from 'styled-components'; -export enum OperationState { +enum OperationState { isSuccess, isFailure, isLoading, From 7dbb70567a51ab66c6dd182706f567e41a4f9696 Mon Sep 17 00:00:00 2001 From: roggc Date: Wed, 12 Jan 2022 09:45:53 +0100 Subject: [PATCH 17/20] panel --- .../FileUploadV2/FileUploadV2.stories.tsx | 3 ++- src/Containers/FileUploadV2/FileUploadV2.tsx | 19 ++++++++++--------- src/Containers/FileUploadV2/Panel.tsx | 14 +------------- src/Containers/FileUploadV2/worker.ts | 2 -- 4 files changed, 13 insertions(+), 25 deletions(-) diff --git a/src/Containers/FileUploadV2/FileUploadV2.stories.tsx b/src/Containers/FileUploadV2/FileUploadV2.stories.tsx index 2f0658415..c66fad41a 100644 --- a/src/Containers/FileUploadV2/FileUploadV2.stories.tsx +++ b/src/Containers/FileUploadV2/FileUploadV2.stories.tsx @@ -2,13 +2,14 @@ import React from 'react'; import { Meta, Story } from '@storybook/react'; import { FileUploadV2, IFileUploadV2Props } from '../../index'; import DropArea from './DropArea'; - +import Panel from './Panel'; export default { title: 'Components/FileUploadV2', component: FileUploadV2, args: { DropArea, + Panel, processFile:(base64StringFile:string)=>{console.log(base64StringFile)} }, } as Meta; diff --git a/src/Containers/FileUploadV2/FileUploadV2.tsx b/src/Containers/FileUploadV2/FileUploadV2.tsx index da27fc630..41fc57abb 100644 --- a/src/Containers/FileUploadV2/FileUploadV2.tsx +++ b/src/Containers/FileUploadV2/FileUploadV2.tsx @@ -4,7 +4,6 @@ import styled from 'styled-components'; import worker from 'workerize-loader!./worker'; // eslint-disable-line import { useMounted } from '@Utils/Hooks'; import Dropzone, { useDropzone } from 'react-dropzone'; -import Panel from './Panel'; // TODO: Add animations if possible (height transitions of the container component (expansion-contraction)) // and fade-in, fade-out effect of the informative panels. @@ -12,13 +11,19 @@ import Panel from './Panel'; const MESSAGE_DURATION = 1500; const NO_BASE64STRINGFILE = 'NO_BASE64STRINGFILE'; -enum OperationState { +export enum OperationState { isSuccess, isFailure, isLoading, isUnknown } +export interface IPanelProps extends React.HTMLAttributes { + operationState?: OperationState; + /** the name of the file */ + name?: string; +} + interface IPanel { /** whether it's loading file, is completed, is failure */ operationState:OperationState; @@ -49,6 +54,8 @@ export interface IFileUploadV2Props isDisabled?: boolean; /** component to render the drop area */ DropArea: React.FC; + /** component to render the informative panel */ + Panel:React.FC; /** if true, failure message will appear even after success operation; its purpose is to test the appearance of the failure message during development */ isTestIsFailure?: boolean; /** @@ -65,6 +72,7 @@ export interface IFileUploadV2Props export const FileUploadV2: React.FC = ({ isDisabled = false, DropArea, + Panel, isTestIsFailure = false, processFile = (base64String: string) => null, messageDuration = MESSAGE_DURATION, @@ -90,12 +98,9 @@ export const FileUploadV2: React.FC = ({ if (base64StringFile === undefined) { return; } - console.log('file name', name); - console.log('informativePanels', informativePanels.panels); const informativePanel = informativePanels.panels.find( (panel) => panel.name === name, ); - console.log('informativePanel', informativePanel); if (informativePanel) { if ( base64StringFile === NO_BASE64STRINGFILE || @@ -117,7 +122,6 @@ export const FileUploadV2: React.FC = ({ ], })); } else { - console.log('processing file'); processFile(base64StringFile); setInformativePanels((prev) => ({ ...prev, @@ -152,7 +156,6 @@ export const FileUploadV2: React.FC = ({ * load array of informative panels and send order to start workers */ const onDrop = useCallback((acceptedFiles: File[]) => { - console.log('dropped'); const newInformativePanels = acceptedFiles.map((file) => { const workerInstance = worker(); return { @@ -163,7 +166,6 @@ export const FileUploadV2: React.FC = ({ }; }); const fileNames = acceptedFiles.map((file) => file.name); - console.log('newInformativePanels', newInformativePanels); setInformativePanels((prev) => ({ ...prev, panels: [...prev.panels, ...newInformativePanels], @@ -176,7 +178,6 @@ export const FileUploadV2: React.FC = ({ // are loaded useEffect(() => { if (informativePanels.startWorkers.length) { - console.log('useEffect', informativePanels.startWorkers); informativePanels.startWorkers.forEach((name) => { const informativePanel = informativePanels.panels.find( (panel) => panel.name === name, diff --git a/src/Containers/FileUploadV2/Panel.tsx b/src/Containers/FileUploadV2/Panel.tsx index 2d0a4cc84..c9fe676fc 100644 --- a/src/Containers/FileUploadV2/Panel.tsx +++ b/src/Containers/FileUploadV2/Panel.tsx @@ -1,18 +1,6 @@ import React, { useCallback } from 'react'; import styled from 'styled-components'; - -enum OperationState { - isSuccess, - isFailure, - isLoading, - isUnknown -} - -interface IPanelProps extends React.HTMLAttributes { - operationState?: OperationState; - /** the name of the file */ - name?: string; -} +import { IPanelProps,OperationState } from './FileUploadV2'; const Panel: React.FC = ({ operationState=OperationState.isUnknown, name='', ...props }) => { const getMessage = useCallback((): string => { diff --git a/src/Containers/FileUploadV2/worker.ts b/src/Containers/FileUploadV2/worker.ts index 4b75576fd..17a094d92 100644 --- a/src/Containers/FileUploadV2/worker.ts +++ b/src/Containers/FileUploadV2/worker.ts @@ -1,6 +1,5 @@ onmessage = (e) => { const { file } = e.data; - console.log('onworker',e); const reader = new FileReader(); reader.onload = () => { let base64StringFile = 'NO_BASE64STRINGFILE'; @@ -14,7 +13,6 @@ onmessage = (e) => { ); } } - console.log('worker;post-message'); postMessage({ base64StringFile,name:file.name }); }; try{ From d5c94e04837d83526da70a97c4c3c3c5976df163 Mon Sep 17 00:00:00 2001 From: roggc Date: Wed, 12 Jan 2022 18:49:13 +0100 Subject: [PATCH 18/20] stories for each component --- src/Containers/DropArea/DropArea.stories.tsx | 20 +++++++++++ .../{FileUploadV2 => DropArea}/DropArea.tsx | 10 +++--- .../FileUploadV2/FileUploadV2.stories.tsx | 8 ++--- src/Containers/Panel/Panel.stories.tsx | 36 +++++++++++++++++++ .../{FileUploadV2 => Panel}/Panel.tsx | 10 +++--- src/Containers/index.ts | 2 ++ 6 files changed, 72 insertions(+), 14 deletions(-) create mode 100644 src/Containers/DropArea/DropArea.stories.tsx rename src/Containers/{FileUploadV2 => DropArea}/DropArea.tsx (88%) create mode 100644 src/Containers/Panel/Panel.stories.tsx rename src/Containers/{FileUploadV2 => Panel}/Panel.tsx (68%) diff --git a/src/Containers/DropArea/DropArea.stories.tsx b/src/Containers/DropArea/DropArea.stories.tsx new file mode 100644 index 000000000..1a5a6d8b9 --- /dev/null +++ b/src/Containers/DropArea/DropArea.stories.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { Meta, Story } from '@storybook/react'; +import { DropArea,IDropAreaProps } from './DropArea'; + +export default { + title: 'Components/DropArea', + component: DropArea, + args: { + }, +} as Meta; + +export const Basic: Story = (args) => ( + +); + +export const IsDragEnterTrue = Basic.bind({}); +IsDragEnterTrue.args={ + ...Basic.args, + isDragEnter:true +} \ No newline at end of file diff --git a/src/Containers/FileUploadV2/DropArea.tsx b/src/Containers/DropArea/DropArea.tsx similarity index 88% rename from src/Containers/FileUploadV2/DropArea.tsx rename to src/Containers/DropArea/DropArea.tsx index 8b8fa47a5..07d7302e2 100644 --- a/src/Containers/FileUploadV2/DropArea.tsx +++ b/src/Containers/DropArea/DropArea.tsx @@ -1,9 +1,11 @@ import React from 'react'; import styled from 'styled-components'; -import {IDropAreaProps} from './FileUploadV2'; +import {IDropAreaProps} from '../FileUploadV2/FileUploadV2'; -const DropArea: React.FC = ({ - isDragEnter, +export {IDropAreaProps}; + +export const DropArea: React.FC = ({ + isDragEnter=false, ...props }) => ( @@ -11,8 +13,6 @@ const DropArea: React.FC = ({ ); -export default DropArea - const DropAreaContainer = styled.div` border: 2px dashed grey; border-radius: 10px; diff --git a/src/Containers/FileUploadV2/FileUploadV2.stories.tsx b/src/Containers/FileUploadV2/FileUploadV2.stories.tsx index c66fad41a..5a393ff55 100644 --- a/src/Containers/FileUploadV2/FileUploadV2.stories.tsx +++ b/src/Containers/FileUploadV2/FileUploadV2.stories.tsx @@ -1,9 +1,9 @@ import React from 'react'; import { Meta, Story } from '@storybook/react'; -import { FileUploadV2, IFileUploadV2Props } from '../../index'; -import DropArea from './DropArea'; -import Panel from './Panel'; - +import { FileUploadV2, IFileUploadV2Props } from './FileUploadV2'; +import {Panel} from '../Panel/Panel'; +import {DropArea} from '../DropArea/DropArea'; + export default { title: 'Components/FileUploadV2', component: FileUploadV2, diff --git a/src/Containers/Panel/Panel.stories.tsx b/src/Containers/Panel/Panel.stories.tsx new file mode 100644 index 000000000..13543efa8 --- /dev/null +++ b/src/Containers/Panel/Panel.stories.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { Meta, Story } from '@storybook/react'; +import { Panel,IPanelProps,OperationState} from './Panel'; + +export default { + title: 'Components/Panel', + component: Panel, + args: { + }, +} as Meta; + +export const Basic: Story = (args) => ( + +); + +export const FileIsLoading = Basic.bind({}); +FileIsLoading.args={ + ...Basic.args, + name:'file A', + operationState:OperationState.isLoading +} + +export const FileIsFailure = Basic.bind({}); +FileIsFailure.args={ + ...Basic.args, + name:'file A', + operationState:OperationState.isFailure +} + +export const FileIsSuccess = Basic.bind({}); +FileIsSuccess.args={ + ...Basic.args, + name:'file A', + operationState:OperationState.isSuccess +} + diff --git a/src/Containers/FileUploadV2/Panel.tsx b/src/Containers/Panel/Panel.tsx similarity index 68% rename from src/Containers/FileUploadV2/Panel.tsx rename to src/Containers/Panel/Panel.tsx index c9fe676fc..678d479b2 100644 --- a/src/Containers/FileUploadV2/Panel.tsx +++ b/src/Containers/Panel/Panel.tsx @@ -1,8 +1,10 @@ import React, { useCallback } from 'react'; import styled from 'styled-components'; -import { IPanelProps,OperationState } from './FileUploadV2'; +import { IPanelProps,OperationState } from '../FileUploadV2/FileUploadV2'; -const Panel: React.FC = ({ operationState=OperationState.isUnknown, name='', ...props }) => { +export {IPanelProps,OperationState}; + +export const Panel: React.FC = ({ operationState=OperationState.isUnknown, name='', ...props }) => { const getMessage = useCallback((): string => { switch (operationState) { case OperationState.isFailure: @@ -18,6 +20,4 @@ const Panel: React.FC = ({ operationState=OperationState.isUnknown, return {getMessage()}; }; -export default Panel; - -const PanelContainer = styled.div``; +const PanelContainer = styled.div``; \ No newline at end of file diff --git a/src/Containers/index.ts b/src/Containers/index.ts index c7c081752..cf0152077 100644 --- a/src/Containers/index.ts +++ b/src/Containers/index.ts @@ -98,3 +98,5 @@ export * from './InfoHeader/InfoHeader'; export * from './StoreSelector/StoreSelector'; export * from './ScreenFlashEffect/ScreenFlashEffect'; export * from './FileUploadV2/FileUploadV2'; +export * from './Panel/Panel'; +export * from './DropArea/DropArea'; From 799da8101078a5d2996badd43f61dbac286d0df4 Mon Sep 17 00:00:00 2001 From: roggc Date: Wed, 12 Jan 2022 23:39:00 +0100 Subject: [PATCH 19/20] delete fileuploadv2 changes --- src/Containers/DropArea/DropArea.stories.tsx | 20 -- src/Containers/DropArea/DropArea.tsx | 42 --- .../FileUploadV2/FileUploadV2.stories.tsx | 25 -- src/Containers/FileUploadV2/FileUploadV2.tsx | 253 ------------------ src/Containers/FileUploadV2/worker.ts | 24 -- src/Containers/Panel/Panel.stories.tsx | 36 --- src/Containers/Panel/Panel.tsx | 23 -- 7 files changed, 423 deletions(-) delete mode 100644 src/Containers/DropArea/DropArea.stories.tsx delete mode 100644 src/Containers/DropArea/DropArea.tsx delete mode 100644 src/Containers/FileUploadV2/FileUploadV2.stories.tsx delete mode 100644 src/Containers/FileUploadV2/FileUploadV2.tsx delete mode 100644 src/Containers/FileUploadV2/worker.ts delete mode 100644 src/Containers/Panel/Panel.stories.tsx delete mode 100644 src/Containers/Panel/Panel.tsx diff --git a/src/Containers/DropArea/DropArea.stories.tsx b/src/Containers/DropArea/DropArea.stories.tsx deleted file mode 100644 index 1a5a6d8b9..000000000 --- a/src/Containers/DropArea/DropArea.stories.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import { Meta, Story } from '@storybook/react'; -import { DropArea,IDropAreaProps } from './DropArea'; - -export default { - title: 'Components/DropArea', - component: DropArea, - args: { - }, -} as Meta; - -export const Basic: Story = (args) => ( - -); - -export const IsDragEnterTrue = Basic.bind({}); -IsDragEnterTrue.args={ - ...Basic.args, - isDragEnter:true -} \ No newline at end of file diff --git a/src/Containers/DropArea/DropArea.tsx b/src/Containers/DropArea/DropArea.tsx deleted file mode 100644 index 07d7302e2..000000000 --- a/src/Containers/DropArea/DropArea.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; -import {IDropAreaProps} from '../FileUploadV2/FileUploadV2'; - -export {IDropAreaProps}; - -export const DropArea: React.FC = ({ - isDragEnter=false, - ...props -}) => ( - - Drag and drop your files here or click to select - -); - -const DropAreaContainer = styled.div` - border: 2px dashed grey; - border-radius: 10px; - padding: 10px; - ${({ isDragEnter }): string => ` - ${ - isDragEnter - ? ` - background-color:#cce6ff; - @keyframes border-dance { - 0% { - background-position: left top, right bottom, left bottom, right top; - } - 100% { - background-position: left 15px top, right 15px bottom , left bottom 15px , right top 15px; - } - } - background-image: linear-gradient(90deg, #3399ff 50%, transparent 50%), linear-gradient(90deg, #3399ff 50%, transparent 50%), linear-gradient(0deg, #3399ff 50%, transparent 50%), linear-gradient(0deg, #3399ff 50%, transparent 50%); - background-repeat: repeat-x, repeat-x, repeat-y, repeat-y; - background-size: 15px 2px, 15px 2px, 2px 15px, 2px 15px; - background-position: left top, right bottom, left bottom, right top; - animation: border-dance .3s infinite linear; - ` - : '' -} - `} -`; \ No newline at end of file diff --git a/src/Containers/FileUploadV2/FileUploadV2.stories.tsx b/src/Containers/FileUploadV2/FileUploadV2.stories.tsx deleted file mode 100644 index 5a393ff55..000000000 --- a/src/Containers/FileUploadV2/FileUploadV2.stories.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react'; -import { Meta, Story } from '@storybook/react'; -import { FileUploadV2, IFileUploadV2Props } from './FileUploadV2'; -import {Panel} from '../Panel/Panel'; -import {DropArea} from '../DropArea/DropArea'; - -export default { - title: 'Components/FileUploadV2', - component: FileUploadV2, - args: { - DropArea, - Panel, - processFile:(base64StringFile:string)=>{console.log(base64StringFile)} - }, -} as Meta; - -export const Basic: Story = (args) => ( - -); - -export const TestIsFailure = Basic.bind({}); -TestIsFailure.args = { - ...Basic.args, - isTestIsFailure:true -}; diff --git a/src/Containers/FileUploadV2/FileUploadV2.tsx b/src/Containers/FileUploadV2/FileUploadV2.tsx deleted file mode 100644 index 41fc57abb..000000000 --- a/src/Containers/FileUploadV2/FileUploadV2.tsx +++ /dev/null @@ -1,253 +0,0 @@ -import React, { useState, useCallback, useEffect } from 'react'; -import styled from 'styled-components'; -// @ts-ignore -import worker from 'workerize-loader!./worker'; // eslint-disable-line -import { useMounted } from '@Utils/Hooks'; -import Dropzone, { useDropzone } from 'react-dropzone'; - -// TODO: Add animations if possible (height transitions of the container component (expansion-contraction)) -// and fade-in, fade-out effect of the informative panels. - -const MESSAGE_DURATION = 1500; -const NO_BASE64STRINGFILE = 'NO_BASE64STRINGFILE'; - -export enum OperationState { - isSuccess, - isFailure, - isLoading, - isUnknown -} - -export interface IPanelProps extends React.HTMLAttributes { - operationState?: OperationState; - /** the name of the file */ - name?: string; -} - -interface IPanel { - /** whether it's loading file, is completed, is failure */ - operationState:OperationState; - /** name of file associated with the informative panel */ - name: string; - /** worker; will do the job of reading the file */ - worker: Worker; - /** the file associated with the informative panel */ - file: File; -} - -interface IInformativePanels { - /** array of panels */ - panels: IPanel[]; - /** names of files already uploaded, or failed, or cancelled */ - makeItDisappear: string[]; - /** names of files for which we want to start workers */ - startWorkers: string[]; -} - -export interface IDropAreaProps extends React.HTMLAttributes { - isDragEnter?: boolean; -} - -export interface IFileUploadV2Props - extends React.HTMLAttributes { - /** whether or not the file upload component is disabled */ - isDisabled?: boolean; - /** component to render the drop area */ - DropArea: React.FC; - /** component to render the informative panel */ - Panel:React.FC; - /** if true, failure message will appear even after success operation; its purpose is to test the appearance of the failure message during development */ - isTestIsFailure?: boolean; - /** - * function to process the file read and transformed to a base64 string; default: does nothing - * @param {string} base64String the file read and transformed to a base64 string - */ - processFile?: (base64String: string) => void; - /** time in ms of the presence of the bottom panel informing the result of the operation (sucess or failure); default value: 1500 */ - messageDuration?: number; -} -/** - * multiple file upload, in parallel, version 2 - */ -export const FileUploadV2: React.FC = ({ - isDisabled = false, - DropArea, - Panel, - isTestIsFailure = false, - processFile = (base64String: string) => null, - messageDuration = MESSAGE_DURATION, - ...props -}): React.ReactElement => { - const isMounted = useMounted(); - const [informativePanels, setInformativePanels] = - useState({ - panels: [], - makeItDisappear: [], - startWorkers: [], - }); - const [isDragEnter, setIsDragEnter] = useState(false); - - /** - * terminate worker and set state of informative panel to success or failure and - * send order to remove informative panel in the future. also do whatever user - * wants to do with the file read in case of success - */ - const onWorkerMessage = useCallback( - (e: any) => { - const { base64StringFile, name } = e.data; - if (base64StringFile === undefined) { - return; - } - const informativePanel = informativePanels.panels.find( - (panel) => panel.name === name, - ); - if (informativePanel) { - if ( - base64StringFile === NO_BASE64STRINGFILE || - isTestIsFailure - ) { - setInformativePanels((prev) => ({ - ...prev, - panels: prev.panels.map((panel) => { - if (panel.name === informativePanel.name) - return { - ...panel, - operationState:OperationState.isFailure - }; - return panel; - }), - makeItDisappear: [ - ...prev.makeItDisappear, - informativePanel.name, - ], - })); - } else { - processFile(base64StringFile); - setInformativePanels((prev) => ({ - ...prev, - panels: prev.panels.map((panel) => { - if (panel.name === informativePanel.name) - return { - ...panel, - operationState:OperationState.isSuccess - }; - return panel; - }), - makeItDisappear: [ - ...prev.makeItDisappear, - informativePanel.name, - ], - })); - } - } - }, - [informativePanels.panels, isTestIsFailure, processFile], - ); - - const onDragEnter = () => { - setIsDragEnter(true); - }; - - const onDragLeave = () => { - setIsDragEnter(false); - }; - - /** - * load array of informative panels and send order to start workers - */ - const onDrop = useCallback((acceptedFiles: File[]) => { - const newInformativePanels = acceptedFiles.map((file) => { - const workerInstance = worker(); - return { - operationState:OperationState.isLoading, - name: file.name, - worker: workerInstance, - file, - }; - }); - const fileNames = acceptedFiles.map((file) => file.name); - setInformativePanels((prev) => ({ - ...prev, - panels: [...prev.panels, ...newInformativePanels], - startWorkers: [...fileNames], - })); - setIsDragEnter(false); - }, []); - - // start workers after files have been droped and array of informative panels - // are loaded - useEffect(() => { - if (informativePanels.startWorkers.length) { - informativePanels.startWorkers.forEach((name) => { - const informativePanel = informativePanels.panels.find( - (panel) => panel.name === name, - ); - if (informativePanel) { - informativePanel.worker.onmessage = onWorkerMessage; - informativePanel.worker.postMessage({ - file: informativePanel.file, - }); - } - }); - setInformativePanels((prev) => ({ - ...prev, - startWorkers: [], - })); - } - }, [informativePanels.startWorkers.length]); - - // make disappear informative panels in the future - useEffect(() => { - if (informativePanels.makeItDisappear.length) { - informativePanels.makeItDisappear.forEach((name) => { - setTimeout(() => { - if (isMounted.current) { - setInformativePanels((prev) => ({ - ...prev, - panels: prev.panels.filter((panel) => { - if (panel.name === name) { - panel.worker.terminate(); - return false; - } - return true; - }), - makeItDisappear: prev.makeItDisappear.filter( - (name_) => name_ !== name, - ), - })); - } - }, messageDuration); - }); - } - }, [informativePanels.makeItDisappear.length]); - - const { getRootProps, getInputProps } = useDropzone({ - onDrop, - onDragEnter, - onDragLeave, - disabled: isDisabled, - }); - - return ( - - - {() => ( -
- - -
- )} -
- {informativePanels.panels.map((panel) => ( - - ))} -
- ); -}; - -const FileUploadV2Container = styled.div` - background-color: white; - border-radius: 10px; - padding: 10px; - width: fit-content; -`; diff --git a/src/Containers/FileUploadV2/worker.ts b/src/Containers/FileUploadV2/worker.ts deleted file mode 100644 index 17a094d92..000000000 --- a/src/Containers/FileUploadV2/worker.ts +++ /dev/null @@ -1,24 +0,0 @@ -onmessage = (e) => { - const { file } = e.data; - const reader = new FileReader(); - reader.onload = () => { - let base64StringFile = 'NO_BASE64STRINGFILE'; - if (reader.result) { - if (typeof reader.result === 'string') { - base64StringFile = btoa(reader.result); - } else { - const bytes = Array.from(new Uint8Array(reader.result)); - base64StringFile = btoa( - bytes.map((item) => String.fromCharCode(item)).join(''), - ); - } - } - postMessage({ base64StringFile,name:file.name }); - }; - try{ - reader.readAsArrayBuffer(file); - }catch(error){ - console.log(error); - postMessage({}); - } -}; \ No newline at end of file diff --git a/src/Containers/Panel/Panel.stories.tsx b/src/Containers/Panel/Panel.stories.tsx deleted file mode 100644 index 13543efa8..000000000 --- a/src/Containers/Panel/Panel.stories.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react'; -import { Meta, Story } from '@storybook/react'; -import { Panel,IPanelProps,OperationState} from './Panel'; - -export default { - title: 'Components/Panel', - component: Panel, - args: { - }, -} as Meta; - -export const Basic: Story = (args) => ( - -); - -export const FileIsLoading = Basic.bind({}); -FileIsLoading.args={ - ...Basic.args, - name:'file A', - operationState:OperationState.isLoading -} - -export const FileIsFailure = Basic.bind({}); -FileIsFailure.args={ - ...Basic.args, - name:'file A', - operationState:OperationState.isFailure -} - -export const FileIsSuccess = Basic.bind({}); -FileIsSuccess.args={ - ...Basic.args, - name:'file A', - operationState:OperationState.isSuccess -} - diff --git a/src/Containers/Panel/Panel.tsx b/src/Containers/Panel/Panel.tsx deleted file mode 100644 index 678d479b2..000000000 --- a/src/Containers/Panel/Panel.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React, { useCallback } from 'react'; -import styled from 'styled-components'; -import { IPanelProps,OperationState } from '../FileUploadV2/FileUploadV2'; - -export {IPanelProps,OperationState}; - -export const Panel: React.FC = ({ operationState=OperationState.isUnknown, name='', ...props }) => { - const getMessage = useCallback((): string => { - switch (operationState) { - case OperationState.isFailure: - return 'something went wrong'; - case OperationState.isSuccess: - return 'completed'; - case OperationState.isLoading: - return `loading ${name} ...`; - default: - return ''; - } - }, [name, operationState]); - return {getMessage()}; -}; - -const PanelContainer = styled.div``; \ No newline at end of file From d8c1f05647ef05d22018f93ac7b2b31343dc82c1 Mon Sep 17 00:00:00 2001 From: roggc Date: Wed, 12 Jan 2022 23:42:13 +0100 Subject: [PATCH 20/20] delete exports in index.ts --- src/Containers/index.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Containers/index.ts b/src/Containers/index.ts index cf0152077..15a9ea2dd 100644 --- a/src/Containers/index.ts +++ b/src/Containers/index.ts @@ -97,6 +97,3 @@ export * from './ReachIndicator/ReachIndicator'; export * from './InfoHeader/InfoHeader'; export * from './StoreSelector/StoreSelector'; export * from './ScreenFlashEffect/ScreenFlashEffect'; -export * from './FileUploadV2/FileUploadV2'; -export * from './Panel/Panel'; -export * from './DropArea/DropArea';