diff --git a/bugs.md b/bugs.md index b16d2d1bd3ab76ee38085c674d43d488208bfc3c..86b72e3c19a29b763e68cab2580d01813cc953ac 100644 --- a/bugs.md +++ b/bugs.md @@ -2,14 +2,16 @@ ## File Item (mosaic) -- on change progress the loader is reredered again and again, I think that the 3 states or layers must be there from the begining +- [SOLVED]on change progress the loader is reredered again and again, I think that the 3 states or layers must be there from the begining "preparing", "uploading", "result" - on cancel, the 2nd layer will dissapear, it will not be any big deal - After uploading, progress must be reiitialized to 0 -- [SOLVED] FileiTEMmAINlAYER WORKS STRANGE AT THE TIME NEW fILEiTEM IS ADDED -- Fileptions (menu collapsed from click in option icon) +- [SOLVED] FileItemMainLayer WORKS STRANGE AT THE TIME NEW fILEiTEM IS ADDED + ## Dropzone +- When no validation, upload removes all files. +- [SOLVED]: action buttons rendered again and again since they were created again every time "value" prop changed - [SOLVED]: Uploading works in 2 times (first time stops after setting progress = UPLOADING.progrss), but fails to recover from the manager. [UPDATED]: Problem is at `useDropzoneFileListUpdater.ts` file. The problem is that hook for updating when user wants to interrupt preparing, is called at the begining of the upload process, with value of undefined in all files. It is probably the last update on localFiles outside Dropzone component. - When file is set from preparing to undefined it can be deleted, however, will appear again if onDelete is called. It would be great to add a reconciliation procedure to support different array sizes in updater hook. Or "canceled" upload status could be added and file Item should not show the "X" button when uploading and canceled. After Upload process, all files with "canceled" upload status should be set to "undefined" again. This can be a workaround. diff --git a/future-features.md b/future-features.md index 7ca731f00a8dcf87cbfde8694da2409ba550871f..4e210cb322c854c32180f820ef18f8ff57f84eff 100644 --- a/future-features.md +++ b/future-features.md @@ -3,11 +3,11 @@ ## UTILS - custom icons -- menu icon for FileItem -- Outside actions or buttons for Dropzone -- header and footer custom props +- menu icon for FileItem ( FileOptions (menu collapsed from click in option icon) ) +- [DONE]: Outside actions or buttons for Dropzone +- [WIP]:header and footer custom props - FileItem: checkbox support -- FileItem: detect when width of image is greater than height or viceversa in order to decide the orientation +- [DONE] FileItem: ( smart prop ) detect when width of image is greater than height or viceversa in order to decide the orientation ## Upload @@ -25,5 +25,6 @@ - Java spring ## dont know if context would be a good idea + - maybe yes for props like custom buttons for file mosaci - custom file thumbnails diff --git a/ideas.md b/ideas.md index 9fe809d7cedfc493b60ae0072adf7e8d177ff62f..c001002bfddcbad888c35291aa9c6e926e202576 100644 --- a/ideas.md +++ b/ideas.md @@ -9,7 +9,7 @@ ## Phrases - Stop pain with developing a complex widget, don't need to create a file upload component from scratch -- If you need to do it from scratch, there is an example [show some basic code] +- If you need to do it from scratch, there is an example [show some basic code] Bellow main page component diff --git a/src/components/demo-components/dropzone-demo/AdvancedDropzoneDemo.jsx b/src/components/demo-components/dropzone-demo/AdvancedDropzoneDemo.jsx index f4e7c34439fa21f54e00db03e4d1cb7919067a95..12665f2920855bc7dd5600f2bd9bce0f3f40f312 100644 --- a/src/components/demo-components/dropzone-demo/AdvancedDropzoneDemo.jsx +++ b/src/components/demo-components/dropzone-demo/AdvancedDropzoneDemo.jsx @@ -64,10 +64,10 @@ export default function AdvancedDropzoneDemo() { onChange={updateFiles} minHeight="195px" value={extFiles} - maxFiles={3} - maxFileSize={2998000 * 20} + /* maxFiles={3} + maxFileSize={2998000 * 20} */ label="Drag'n drop files here or click to browse" - accept=".png,image/*, video/*" + // accept=".png,image/*, video/*" uploadConfig={{ /* autoUpload: true */ method: "POST", diff --git a/src/components/demo-components/filemosaic-demo/DemoFileMosaicImagePreview.tsx b/src/components/demo-components/filemosaic-demo/DemoFileMosaicImagePreview.tsx index 5d575243d5182c50f74a139662d8a870d83249f5..5b0610bca92675a7d3c13c353ca637b1287a2d92 100644 --- a/src/components/demo-components/filemosaic-demo/DemoFileMosaicImagePreview.tsx +++ b/src/components/demo-components/filemosaic-demo/DemoFileMosaicImagePreview.tsx @@ -35,7 +35,7 @@ const DemoFileMosaicImagePreview: React.FC<DemoFileMosaicImagePreviewProps> = ( preview /> ) : ( - <FileInputButton value={value ? [value] : []} onChange={updateFile} /> + <FileInputButton value={value ? [value] : []} onChange={updateFile} accept="image/*"/> )} <FileMosaic {...sampleFileProps} alwaysActive info /> </> diff --git a/src/components/demo-components/filemosaic-demo/DemoFileMosaicValidation.jsx b/src/components/demo-components/filemosaic-demo/DemoFileMosaicValidation.jsx index 6470472b5357998e5b472365fd297dc9676aec62..93df5d57eee3e6c7faa65cb96ba82b082efd42c0 100644 --- a/src/components/demo-components/filemosaic-demo/DemoFileMosaicValidation.jsx +++ b/src/components/demo-components/filemosaic-demo/DemoFileMosaicValidation.jsx @@ -13,14 +13,14 @@ const sampleFilesProps = [ size: 28 * 1024 * 1024, type: "image/png", name: "valid file created from props.png", - valid: true, + valid: false, }, { id: "fileId-3", size: 28 * 1024 * 1024, type: "image/jpeg", name: "non valid file created from props.jpg", - valid: false, + valid: true, }, ]; diff --git a/src/files-ui/components/file-mosaic/components/FileMosaicUploadLayer/FileMosaicUploadLayer.tsx b/src/files-ui/components/file-mosaic/components/FileMosaicUploadLayer/FileMosaicUploadLayer.tsx index 4db3c99550fe0a0a08f1138be195cf7915317924..5359ad331e4e257fe9746fac3e149c30ba2cf5b1 100644 --- a/src/files-ui/components/file-mosaic/components/FileMosaicUploadLayer/FileMosaicUploadLayer.tsx +++ b/src/files-ui/components/file-mosaic/components/FileMosaicUploadLayer/FileMosaicUploadLayer.tsx @@ -7,14 +7,16 @@ import { LocalLabels, UPLOADSTATUS, } from "../../../../core"; -import { - CheckCircle, - Clear, - //CloudDone, - DoDisturb, - //UploadError, -} from "../../../icons"; +import { CheckCircle, Clear, DoDisturb } from "../../../icons"; import { DynamicLoader } from "../../../loader"; +import { + AbortedStatus, + EmptyStatus, + ErrorStatus, + PreparingStatus, + SuccessStatus, + UploadingStatus, +} from "../../../file-status"; const FileMosaicUploadLayer: React.FC<FileMosaicUploadLayerProps> = ( props: FileMosaicUploadLayerProps @@ -48,145 +50,54 @@ const FileMosaicUploadLayer: React.FC<FileMosaicUploadLayerProps> = ( 0 - (statusHistory.length - 1) * 132 + "px"; }; React.useEffect(() => { - if (statusHistory.length > 1) { - elevate(); - } + if (statusHistory.length > 1) elevate(); // eslint-disable-next-line }, [statusHistory.length]); - const PreparingStatus = React.useMemo( - () => () => - ( - <React.Fragment> - <InfiniteLoader onClick={onCancel} size={65} /> - <span>{FileItemStatusLocalizer.preparing as string}</span> - </React.Fragment> - ), - [] - ); - const UploadingStatus = React.useMemo( - () => () => - ( - <React.Fragment> - {progress !== undefined ? ( - <DynamicLoader - size={70} - x={35} - y={35} - radius={32} - percentage={progress} - width={6} - hidePerncentage={progress === undefined || onAbort !== undefined} - onClick={onAbort} - /> - ) : ( - <InfiniteLoader onClick={onAbort} size={70} /> - )} - <span> {FileItemStatusLocalizer.uploading as string}</span> - </React.Fragment> - ), - [progress, onAbort, FileItemStatusLocalizer] - ); - - const SuccessStatus = () => { - return ( - <React.Fragment> - <CheckCircle - color="#4caf50" - size={65} - //style={{ backgroundColor: "rgba(255,255,255,0.8)", borderRadius: "50%", padding: 8 }} - /> - <span> {FileItemStatusLocalizer.success as string}</span> - </React.Fragment> - ); - }; - const ErrorStatus = () => { - return ( - <React.Fragment> - <Clear - color="rgba(255,255,255,0.4)" - style={{ - backgroundColor: "rgba(244, 67, 54, 0.8)", - borderRadius: "50%", - }} - size={65} - /> - <span> {FileItemStatusLocalizer.error as string}</span> - </React.Fragment> - ); - }; - const AbortedStatus = () => { - return ( - <React.Fragment> - <DoDisturb color="#f44336" size={65} /> - <span> {FileItemStatusLocalizer.aborted as string}</span> - </React.Fragment> - ); - }; - const Empty = () => { - return ( - <React.Fragment> - <div style={{ width: "100%", height: "132px" }}> - {/* <span> VACIOOOOO</span> */} - </div> - </React.Fragment> - ); - }; - - const StatusSelector = (status: UPLOADSTATUS | undefined) => { - switch (status) { - /* case "preparing": - return <PreparingStatus />; - case "uploading": - return <UploadingStatus />; */ - case "error": - return <ErrorStatus />; - case "success": - return <SuccessStatus />; - case "aborted": - return <AbortedStatus />; - default: - return <Empty />; - } - }; //default phase return ( <div className={"elevation-layer-container"} ref={elevationContainerRef}> <div className="elevation-list" ref={listContainerStoryRef}> {statusHistory.map((status, index) => { - return ( - <div className="elevation-item" key={index + 1}> - {status === "preparing" ? ( - <React.Fragment> - <InfiniteLoader onClick={onCancel} size={65} /> - <span>{FileItemStatusLocalizer.preparing as string}</span> - </React.Fragment> - ) : status === "uploading" ? ( - <React.Fragment> - {progress !== undefined ? ( - <DynamicLoader - size={70} - x={35} - y={35} - radius={32} - percentage={progress} - width={6} - hidePerncentage={ - progress === undefined || onAbort !== undefined - } - onClick={onAbort} - /> - ) : ( - <InfiniteLoader onClick={onAbort} size={70} /> - )} - <span> {FileItemStatusLocalizer.uploading as string}</span> - </React.Fragment> - ) : ( - StatusSelector(status) - )} - </div> - ); + switch (status) { + case "preparing": + return ( + <div className="elevation-item" key={index + 1}> + <PreparingStatus onCancel={onCancel}/> + </div> + ); + case "uploading": + return ( + <div className="elevation-item" key={index + 1}> + <UploadingStatus onAbort={onAbort} progress={progress}/> + </div> + ); + case "error": + return ( + <div className="elevation-item" key={index + 1}> + <ErrorStatus /> + </div> + ); + case "success": + return ( + <div className="elevation-item" key={index + 1}> + <SuccessStatus /> + </div> + ); + case "aborted": + return ( + <div className="elevation-item" key={index + 1}> + <AbortedStatus /> + </div> + ); + default: + return ( + <div className="elevation-item" key={index + 1}> + <EmptyStatus /> + </div> + ); + } })} </div> </div> diff --git a/src/files-ui/components/file-status/AbortedStatus.tsx b/src/files-ui/components/file-status/AbortedStatus.tsx new file mode 100644 index 0000000000000000000000000000000000000000..f195e8d95de9ab794dbeda164d37bc17459eb449 --- /dev/null +++ b/src/files-ui/components/file-status/AbortedStatus.tsx @@ -0,0 +1,21 @@ +import * as React from "react"; +import { FileItemLocalizerSelector, LocalLabels } from "../../core"; +import { DoDisturb } from "../icons"; +import { FileStatusProps } from "./FileStatusProps"; +interface AbortedStatusProps extends FileStatusProps {} + +const AbortedStatus: React.FC<AbortedStatusProps> = ( + props: AbortedStatusProps +) => { + const { localization, size } = props; + const FileItemStatusLocalizer: LocalLabels = FileItemLocalizerSelector( + localization + ).status as LocalLabels; + return ( + <React.Fragment> + <DoDisturb color="#f44336" size={size || 65} /> + <span> {FileItemStatusLocalizer.aborted as string}</span> + </React.Fragment> + ); +}; +export default AbortedStatus; diff --git a/src/files-ui/components/file-status/EmptyStatus.tsx b/src/files-ui/components/file-status/EmptyStatus.tsx new file mode 100644 index 0000000000000000000000000000000000000000..9b872accd7603f8a9b5e7896e6824edf3c7ce9b9 --- /dev/null +++ b/src/files-ui/components/file-status/EmptyStatus.tsx @@ -0,0 +1,20 @@ +import * as React from "react"; +interface EmptyStatusProps { + height?: string | number; +} +const EmptyStatus: React.FC<EmptyStatusProps> = (props: EmptyStatusProps) => { + const { height } = props; + const finalHeight: string = !height + ? "132px" + : typeof height === "number" + ? `${height}px` + : height; + return ( + <React.Fragment> + <div style={{ width: "100%", height: finalHeight }}> + {/* <span> EMPTY </span> */} + </div> + </React.Fragment> + ); +}; +export default EmptyStatus; diff --git a/src/files-ui/components/file-status/ErrorStatus.tsx b/src/files-ui/components/file-status/ErrorStatus.tsx new file mode 100644 index 0000000000000000000000000000000000000000..b17f6bde8f44446dc232bfe0196a371a921ccf09 --- /dev/null +++ b/src/files-ui/components/file-status/ErrorStatus.tsx @@ -0,0 +1,26 @@ +import * as React from "react"; +import { FileItemLocalizerSelector, LocalLabels } from "../../core"; +import { Clear } from "../icons"; +import { FileStatusProps } from "./FileStatusProps"; +interface ErrorStatusProps extends FileStatusProps {} + +const ErrorStatus: React.FC<ErrorStatusProps> = (props: ErrorStatusProps) => { + const { localization, size } = props; + const FileItemStatusLocalizer: LocalLabels = FileItemLocalizerSelector( + localization + ).status as LocalLabels; + return ( + <React.Fragment> + <Clear + color="rgba(255,255,255,0.4)" + style={{ + backgroundColor: "rgba(244, 67, 54, 0.8)", + borderRadius: "50%", + }} + size={size || 65} + /> + <span> {FileItemStatusLocalizer.error as string}</span> + </React.Fragment> + ); +}; +export default ErrorStatus; diff --git a/src/files-ui/components/file-status/FileStatusProps.ts b/src/files-ui/components/file-status/FileStatusProps.ts new file mode 100644 index 0000000000000000000000000000000000000000..442c799b44da6b29d2bee336182cf3d29455e87b --- /dev/null +++ b/src/files-ui/components/file-status/FileStatusProps.ts @@ -0,0 +1,6 @@ +import { Localization } from "../../core"; + +export type FileStatusProps = { + localization?: Localization; + size?: number; +} \ No newline at end of file diff --git a/src/files-ui/components/file-status/PreparingStatus.tsx b/src/files-ui/components/file-status/PreparingStatus.tsx new file mode 100644 index 0000000000000000000000000000000000000000..ba5e813c837b3b14c4dae4c4795e28cd18a8cb04 --- /dev/null +++ b/src/files-ui/components/file-status/PreparingStatus.tsx @@ -0,0 +1,26 @@ +import * as React from "react"; +import { FileItemLocalizerSelector, LocalLabels } from "../../core"; +import InfiniteLoader from "../loader/InfiniteLoader/InfiniteLoader"; +import { FileStatusProps } from "./FileStatusProps"; + +export type PreparingStatusProps = { + [P in keyof FileStatusProps]: FileStatusProps[P]; +} & { + onCancel?: Function; +}; + +const PreparingStatus: React.FC<PreparingStatusProps> = ( + props: PreparingStatusProps +) => { + const { onCancel, localization, size } = props; + const FileItemStatusLocalizer: LocalLabels = FileItemLocalizerSelector( + localization + ).status as LocalLabels; + return ( + <React.Fragment> + <InfiniteLoader onClick={onCancel} size={size || 65} /> + <span>{FileItemStatusLocalizer.preparing as string}</span> + </React.Fragment> + ); +}; +export default PreparingStatus; diff --git a/src/files-ui/components/file-status/SuccessStatus.tsx b/src/files-ui/components/file-status/SuccessStatus.tsx new file mode 100644 index 0000000000000000000000000000000000000000..76eaf5ab6a88c3d63176383b486c5bfa367cf149 --- /dev/null +++ b/src/files-ui/components/file-status/SuccessStatus.tsx @@ -0,0 +1,24 @@ +import * as React from "react"; +import { FileItemLocalizerSelector, LocalLabels } from "../../core"; +import { CheckCircle } from "../icons"; +import { FileStatusProps } from "./FileStatusProps"; +interface SuccessStatusProps extends FileStatusProps {} +const SuccessStatus: React.FC<SuccessStatusProps> = ( + props: SuccessStatusProps +) => { + const { localization, size } = props; + const FileItemStatusLocalizer: LocalLabels = FileItemLocalizerSelector( + localization + ).status as LocalLabels; + return ( + <React.Fragment> + <CheckCircle + color="#4caf50" + size={size || 65} + //style={{ backgroundColor: "rgba(255,255,255,0.8)", borderRadius: "50%", padding: 8 }} + /> + <span> {FileItemStatusLocalizer.success as string}</span> + </React.Fragment> + ); +}; +export default SuccessStatus; diff --git a/src/files-ui/components/file-status/UploadingStatus.tsx b/src/files-ui/components/file-status/UploadingStatus.tsx new file mode 100644 index 0000000000000000000000000000000000000000..98f20d0785627347bace70a853a3ee0a3e624863 --- /dev/null +++ b/src/files-ui/components/file-status/UploadingStatus.tsx @@ -0,0 +1,41 @@ +import * as React from "react"; +import { FileItemLocalizerSelector, LocalLabels } from "../../core"; +import { DynamicLoader } from "../loader"; +import InfiniteLoader from "../loader/InfiniteLoader/InfiniteLoader"; +import { FileStatusProps } from "./FileStatusProps"; + +export type UploadingStatusProps = { + [P in keyof FileStatusProps]: FileStatusProps[P]; +} & { + onAbort?: Function; + progress?: number; +}; + +const UploadingStatus: React.FC<UploadingStatusProps> = ( + props: UploadingStatusProps +) => { + const { localization, size, onAbort, progress } = props; + const FileItemStatusLocalizer: LocalLabels = FileItemLocalizerSelector( + localization + ).status as LocalLabels; + return ( + <React.Fragment> + {progress !== undefined ? ( + <DynamicLoader + size={70} + x={35} + y={35} + radius={32} + percentage={progress} + width={6} + hidePerncentage={progress === undefined || onAbort !== undefined} + onClick={onAbort} + /> + ) : ( + <InfiniteLoader onClick={onAbort} size={size || 70} /> + )} + <span> {FileItemStatusLocalizer.uploading as string}</span> + </React.Fragment> + ); +}; +export default UploadingStatus; diff --git a/src/files-ui/components/file-status/index.ts b/src/files-ui/components/file-status/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..8cf5f461dad285e47bf8443f4c4482a55119a3da --- /dev/null +++ b/src/files-ui/components/file-status/index.ts @@ -0,0 +1,20 @@ +export { default as AbortedStatus } from "./AbortedStatus"; +export * from "./AbortedStatus"; + +export { default as EmptyStatus } from "./EmptyStatus"; +export * from "./EmptyStatus"; + +export { default as ErrorStatus } from "./ErrorStatus"; +export * from "./ErrorStatus"; + +export { default as PreparingStatus } from "./PreparingStatus"; +export * from "./PreparingStatus"; + +export { default as SuccessStatus } from "./SuccessStatus"; +export * from "./SuccessStatus"; + +export { default as UploadingStatus } from "./UploadingStatus"; +export * from "./UploadingStatus"; + + +export type { FileStatusProps } from "./FileStatusProps"; \ No newline at end of file