diff --git a/bugs.md b/bugs.md new file mode 100644 index 0000000000000000000000000000000000000000..6ff2e9071d1c5d0f99e794156f94c5d211487b27 --- /dev/null +++ b/bugs.md @@ -0,0 +1,25 @@ +# BUGS + +## File Item (mosaic) + +- 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) + +## Dropzone + +- [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. + +- [SOLVED] Dropzpne is afected by adding more files as children +- offset should not be used, instead a padding, given header or footer +- When layer is visible, border in the root container must dissapear + +## Tooltip + +- prints console.log() every time I hover FileItem, even when no message is sent + +## Drop Layer + +- prints the classname everytime I drop files o select files diff --git a/features.md b/features.md new file mode 100644 index 0000000000000000000000000000000000000000..3247d94e5ac452329328d46fb251a3390c6dd4e1 --- /dev/null +++ b/features.md @@ -0,0 +1,36 @@ +# Files-ui Features + +## Upload to a server + +- Upload File object +- Upload Form Data +- Upload ExtFile +- Upload with custom headers +- Upload with additional data +- Upload adding callbacks for progress and abort and load + +## Valid + +- Validate with accept prop +- Validate with maxFileSize prop +- Validate with maxFiles prop + +## Read + +- Read as URL +- Read as text +- Read as base64 +- Read adding callbacks for abort and progress and load +- reduce the size of an image (not size , but resolution, other word) + +## UI Components + +- Dropzone +- InputButon +- Avatar +- ImagePreview +- VideoPreview +- PDFPreview +- JsonPreview fix rc-highlight +- FullScreenPreview +- DropLayer diff --git a/future-features.md b/future-features.md new file mode 100644 index 0000000000000000000000000000000000000000..7ca731f00a8dcf87cbfde8694da2409ba550871f --- /dev/null +++ b/future-features.md @@ -0,0 +1,29 @@ +# Future Possible Features + +## UTILS + +- custom icons +- menu icon for FileItem +- Outside actions or buttons for Dropzone +- 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 + +## Upload + +- upload multiple files +- chuncked uploads +- upload concurrent + +## Integrations upload + +- aws S3 +- azure +- google cloud platform (drive) +- dropbox +- firebase +- 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 new file mode 100644 index 0000000000000000000000000000000000000000..9fe809d7cedfc493b60ae0072adf7e8d177ff62f --- /dev/null +++ b/ideas.md @@ -0,0 +1,18 @@ +# Files UI Ideas + +## video + +-small videos for each feature tutorial, after compilig .... "unstopable from Sia" + +- dragon ball OST + +## 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] + + + +## MIgrating from dropzone-ui + +## Migrating from react-dropzone diff --git a/src/components/MainMenu/MainMenuSideBar.tsx b/src/components/MainMenu/MainMenuSideBar.tsx index 8c0c3eb03e6aca61b2decfa7238b4792a0aae3e4..74e6a1e27af2ed95d45d7c15e7a4686641b3ae12 100644 --- a/src/components/MainMenu/MainMenuSideBar.tsx +++ b/src/components/MainMenu/MainMenuSideBar.tsx @@ -46,15 +46,20 @@ export default function MainMenuSideBar(props: MainMenuSideBarProps) { onClick: () => navigate("/components/filemosaic"), }, { - label: "FileInputButton", + label: "InputButton", index: 23, - onClick: () => navigate("/components/fileinputbutton"), + onClick: () => navigate("/components/inputbutton"), }, { label: "FileCard", index: 24, onClick: () => navigate("/components/filecard"), }, + { + label: "Avatar", + index: 25, + onClick: () => navigate("/components/avatar"), + }, ], }, { @@ -75,9 +80,9 @@ export default function MainMenuSideBar(props: MainMenuSideBarProps) { onClick: () => navigate("/api/filemosaic"), }, { - label: "FileInputButton", + label: "InputButton", index: 33, - onClick: () => navigate("/api/fileinputbutton"), + onClick: () => navigate("/api/inputbutton"), }, { label: "FileCard", @@ -99,6 +104,11 @@ export default function MainMenuSideBar(props: MainMenuSideBarProps) { index: 34, onClick: () => navigate("/api/videopreview"), }, + { + label: "Avatar", + index: 35, + onClick: () => navigate("/api/avatar"), + }, ], }, { @@ -223,7 +233,7 @@ export default function MainMenuSideBar(props: MainMenuSideBarProps) { {subMenu && ( <Collapse - in={isOpen } + in={isOpen} timeout="auto" unmountOnExit key={"collapse-submenu" + indexBase} @@ -268,7 +278,8 @@ export default function MainMenuSideBar(props: MainMenuSideBarProps) { <ListItemButton style={{ padding: "2px 20px" }} key={indexBase} - selected={subMenu === undefined && selectedIndex === index} + // selected={subMenu === undefined && selectedIndex === index} + selected={isOpen && selectedIndex === index} onClick={(event) => handleListItemClick( event, @@ -293,7 +304,7 @@ export default function MainMenuSideBar(props: MainMenuSideBarProps) { {subMenu && ( <Collapse - in={isOpen } + in={isOpen} timeout="auto" unmountOnExit key={"collapse-submenu" + indexBase} diff --git a/src/components/MainPage/MainFooter.jsx b/src/components/MainPage/MainFooter.jsx index b73c5756dd1ebb076b4530e40dd4b35f1a31bf9b..e91afb003980bfe0fdda759af31443a40a5261ed 100644 --- a/src/components/MainPage/MainFooter.jsx +++ b/src/components/MainPage/MainFooter.jsx @@ -9,7 +9,7 @@ const MainFooter = (props) => { style={{ display:"flex", flexDirection:"row", alignItems:"center" }} > <img className="fui-logo-img" src={logo_blue} width="38px" /> - <img className="fui-logo-text-img" src={logo_white_ext} height="18px" /> + <img className="fui-logo-text-img" src={logo_white_ext} height="14px" /> </div> <p>{" | "}Copyright © 2023</p> </footer> diff --git a/src/components/MainPage/MainNavBar.jsx b/src/components/MainPage/MainNavBar.jsx index 5a6a0ef2548b6bce9d60d671a97e779037c3d0c5..e7142fd119e21d5c0a8765c2b9906ef48c2eb9e5 100644 --- a/src/components/MainPage/MainNavBar.jsx +++ b/src/components/MainPage/MainNavBar.jsx @@ -6,9 +6,12 @@ import { IconButton, Tooltip, Typography } from "@mui/material"; import logo_text_blue from "../../static/files-ui-logo-text-med.png"; import logo_text_blue_dark from "../../static/files-ui-logo-text-med-dark.png"; - - -const MainNavBar = ({ darkModeOn, logo_blue, logo_blue_dark, handleDarkMode }) => { +const MainNavBar = ({ + darkModeOn, + logo_blue, + logo_blue_dark, + handleDarkMode, +}) => { const handleGoGitRepo = () => { window.open("https://github.com/files-ui", "_blank"); }; @@ -17,27 +20,17 @@ const MainNavBar = ({ darkModeOn, logo_blue, logo_blue_dark, handleDarkMode }) = <nav className="filesui-nav"> <div className="filesui-nav-container"> <div className="left-part"> - <div - className={ - "filesui-nav-logo-container" - } - > + <div className={"filesui-nav-logo-container"}> <img className={"filesui-nav-logo"} // src={!darkModeOn ? logo_blue : logoLight} - src={darkModeOn?logo_blue_dark:logo_blue} + src={darkModeOn ? logo_blue_dark : logo_blue} alt="files-ui-main-logo" /> </div> - {/* <Typography variant="h5" noWrap component="div" color="primary"> - Files ui - </Typography> */} - {/* <p className="filesui-nav-text-logo"> - <span className="gradient-span">Files UI</span> - </p> */} <img - height={"20px"} + height={"18px"} src={darkModeOn ? logo_text_blue_dark : logo_text_blue} alt="files-ui-main-logo-text" /> diff --git a/src/components/MainPage/MainRight/FileMosaicImageVideoPreviews.tsx b/src/components/MainPage/MainRight/FileMosaicImageVideoPreviews.tsx index 7b9428d95d2864acb8354b96ebbd4dd86b72aeb3..9cb19d33eceeec31ad4c863805a031fb6459cc0e 100644 --- a/src/components/MainPage/MainRight/FileMosaicImageVideoPreviews.tsx +++ b/src/components/MainPage/MainRight/FileMosaicImageVideoPreviews.tsx @@ -30,7 +30,9 @@ const FileMosaicImageVideoPreviews: React.FC< "https://files-ui-temp-storage.s3.amazonaws.com/2029385a4ed32ff10beeb94c0585e8ac1a8c377c68d22ef25ce5863694a5499e.mp4" ); //setVideoSrc(videoSource); - setVideoSrc("https://files-ui-temp-storage.s3.amazonaws.com/2029385a4ed32ff10beeb94c0585e8ac1a8c377c68d22ef25ce5863694a5499e.mp4"); + // + setVideoSrc("https://files-ui-temp-storage.s3.amazonaws.com/2029385a4ed32ff10beeb94c0585e8ac1a8c377c68d22ef25ce5863694a5499e.mp4"); + // setVideoSrc("https://www.w3schools.com/tags/movie.mp4"); }; return ( diff --git a/src/components/demo-components/avatar-demo/BasicDemoAvatar.tsx b/src/components/demo-components/avatar-demo/BasicDemoAvatar.tsx new file mode 100644 index 0000000000000000000000000000000000000000..b64cf952e160fb5b4bb7fabdd781c11ec40229ad --- /dev/null +++ b/src/components/demo-components/avatar-demo/BasicDemoAvatar.tsx @@ -0,0 +1,43 @@ +import * as React from "react"; +import { Avatar } from "../../../files-ui"; +import { ServerResponse, uploadFile } from "../../../files-ui/core"; +const REMOTE = + "https://files-ui-express-static-file-storage.vercel.app/39d33dff2d41b522c1ea276c4b82507f96b9699493d2e7b3f5c864ba743d9503"; + +const BasicDemoAvatar = () => { + const [avatarSrc, setAvatarSrc] = React.useState<string | undefined>( + "https://files-ui-temp-storage.s3.amazonaws.com/3b3b28b79c49f52ef1d89a35337797532b9cf4b5f3a00678e6f775c974dfbd56.png" + ); + const [isUloading, setIsUploading] = React.useState<boolean>(false); + + const handleChange2 = async (file: File) => { + const endpoint: string = REMOTE + "/file/28048465460"; + setIsUploading(true); + try { + const res: ServerResponse = await uploadFile(file, endpoint); + if (!res.success) alert(res.message); + else { + const { URL } = res.payload; + setAvatarSrc(URL); + } + setIsUploading(false); + } catch (error) { + console.log("ERROR:", error); + alert("ERROR ON UPLOAD"); + setIsUploading(false); + } + }; + + return ( + <React.Fragment> + <Avatar + src={avatarSrc} + //variant="circle" + style={{ width: "280px", height: "280px" }} + onChange={handleChange2} + isUloading={isUloading} + /> + </React.Fragment> + ); +}; +export default BasicDemoAvatar; diff --git a/src/files-ui/components/avatar/Avatar.scss b/src/files-ui/components/avatar/Avatar.scss index afd13e3dd8b6712de1a45ce72b887d2ef96cee3b..d219ea834949fdb4f67866030e2c99b51ba6b6b1 100644 --- a/src/files-ui/components/avatar/Avatar.scss +++ b/src/files-ui/components/avatar/Avatar.scss @@ -3,18 +3,24 @@ height: 200px; position: relative; background-color: transparent; - + overflow: hidden; + display: flex; + align-items: center; + justify-content: center; + background-color: rgba(128, 128, 128, 0.486); + border-radius: 10px; + &.square { + border-radius: 0px; + } + &.circle { + border-radius: 50%; + } .fui-avatar-image { - &.square { - border-radius: 10px; - } - overflow: hidden; - background-color: rgba(128, 128, 128, 0.486); - position: absolute; - left: 0; - top: 0; - width: 100%; - height: 100%; + //width: 100%; + //height: 100%; + background-repeat: no-repeat; + background-size: cover; + background-position: center; } &:hover { .fui-avatar-label { @@ -24,9 +30,6 @@ } } .fui-avatar-label { - &.square { - border-radius: 10px; - } &.hide { display: none; } @@ -43,6 +46,7 @@ align-items: center; justify-content: center; text-align: center; + flex-direction: column; &:hover { background-color: rgba(71, 71, 71, 0.74); display: flex; diff --git a/src/files-ui/components/avatar/Avatar.tsx b/src/files-ui/components/avatar/Avatar.tsx index 42b2bd64100bef4f1deee3f8d8e2d5f53fda823a..57dc59882e86275e390ee4a9754b7354b8b85127 100644 --- a/src/files-ui/components/avatar/Avatar.tsx +++ b/src/files-ui/components/avatar/Avatar.tsx @@ -9,6 +9,9 @@ import { import InputHidden from "../input-hidden/InputHidden"; import { useAvatarStyle } from "./useAvatarStyle"; import { DynamicSheet, DynamiCSS } from "@dynamicss/dynamicss"; +import { ImagePreview } from "../previews"; +import InfiniteLoader from "../loader/InfiniteLoader/InfiniteLoader"; +import Layer from "../file-mosaic/components/file-mosaic-layer/Layer"; const Avatar: React.FC<AvatarProps> = (props: AvatarProps) => { const { style, @@ -20,7 +23,10 @@ const Avatar: React.FC<AvatarProps> = (props: AvatarProps) => { readOnly, variant, borderRadius, + uploadingLabel, + isUloading, onError, + smart, } = mergeProps(props, defaultAvatarProps); const inputRef: React.RefObject<HTMLInputElement> = @@ -28,6 +34,8 @@ const Avatar: React.FC<AvatarProps> = (props: AvatarProps) => { const isStyleInjected: boolean = useAvatarStyle(borderRadius); + //const [isUloading, setIsUploading] = React.useState<boolean>(false); + const avatarClassNameContainer: string = setAvatarClassNameContainer(variant); const avatarClassNameLayerInfo: string = setAvatarClassNameLayerInfo(variant); @@ -56,33 +64,50 @@ const Avatar: React.FC<AvatarProps> = (props: AvatarProps) => { if (isStyleInjected) { return ( - <div className="fui-avatar-main-container" style={style}> - {/**Layer 1 */} - {src ? ( - <img - className="fui-avatar-image" - height={"100%"} - width={"100%"} - src={src} - alt={alt} - onError={handleError} - /> - ) : ( - <p className={"fui-avatar-label"}>{emptyLabel}</p> - )} - {/**Layer 2 */} - {!readOnly && ( - <p className={"fui-avatar-label hide"} onClick={handleClick}> - {src ? changeLabel : emptyLabel} - <InputHidden - multiple={false} - accept={"image/*"} - onChange={handleChangeInput} - inputRef={inputRef} - />{" "} - </p> - )} - </div> + <React.Fragment> + <div + className={`fui-avatar-main-container${ + variant === "circle" ? " circle" : "" + }`} + style={style} + > + {/**Layer 1 */} + {isUloading ? ( + <Layer visible={isUloading}> + <div className={"fui-avatar-label"}> + <InfiniteLoader /> + {uploadingLabel} + </div> + </Layer> + ) : src ? ( + <> + <ImagePreview + className={`fui-avatar-image`} + src={src} + alt={alt} + onError={handleError} + smart={smart} + /> + </> + ) : ( + <div className={"fui-avatar-label"}>{emptyLabel}</div> + )} + {/**Layer 2 */} + {!readOnly && ( + <> + <p className={"fui-avatar-label hide"} onClick={handleClick}> + {src ? changeLabel : emptyLabel} + </p> + <InputHidden + multiple={false} + accept={""} + onChange={handleChangeInput} + inputRef={inputRef} + /> + </> + )} + </div> + </React.Fragment> ); } return <React.Fragment></React.Fragment>; diff --git a/src/files-ui/components/avatar/AvatarProps.ts b/src/files-ui/components/avatar/AvatarProps.ts index 628092378091954012d742b0de92b312c7bc9e26..55e484a54b1ed6a84375b1a6c7096f12d9b49b85 100644 --- a/src/files-ui/components/avatar/AvatarProps.ts +++ b/src/files-ui/components/avatar/AvatarProps.ts @@ -11,15 +11,24 @@ export interface AvatarFullProps extends OverridableComponentProps { alt?: string, emptyLabel?: string; + uploadingLabel?: string; changeLabel?: string; /** - * if a src given, then avanatr will show the image + * if a src is given, then avatar will show the image * or a file error message and will not allow * the user to change the picture. Also, layer on hover will not be shown */ readOnly?: boolean; + isUloading?: boolean; + onError?: React.ReactEventHandler<HTMLImageElement>; + /** + * If true, images will be analized and showed according their orientation + * orientation can be landscape if height < width. + * In that case height will be set to 100%. Otherwise width will be set to 100% + */ + smart?: boolean; } export declare type AvatarProps = { @@ -33,5 +42,7 @@ export const defaultAvatarProps: AvatarProps = alt: `avatar`, emptyLabel: "Agregar foto", changeLabel: "Cambiar foto", - readOnly: false + uploadingLabel: "Uploading...", + readOnly: false, + smart: false, } \ No newline at end of file diff --git a/src/files-ui/components/avatar/index.ts b/src/files-ui/components/avatar/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..81cfdf3693b271542d3e875c09ba7f80a2394c73 --- /dev/null +++ b/src/files-ui/components/avatar/index.ts @@ -0,0 +1,2 @@ +export { default as Avatar } from "./Avatar"; +export * from "./Avatar"; \ No newline at end of file diff --git a/src/files-ui/components/avatar/useAvatarStyle.ts b/src/files-ui/components/avatar/useAvatarStyle.ts index 4636b144ecae527b353dc059df2ab161677a6eda..fd52492a620425aabbcd978bbb37f52da3e35927 100644 --- a/src/files-ui/components/avatar/useAvatarStyle.ts +++ b/src/files-ui/components/avatar/useAvatarStyle.ts @@ -26,10 +26,23 @@ export const useAvatarStyle = (borderRadius: string | undefined): boolean => { } React.useEffect(() => { - /* if (!borderRadius) { - DynamiCSS.removeStyleSheet(idAvatarStyles); - return; - } */ + return () => { + console.log("avatar, deleting init", styleInjected, idAvatarStyles); + if (styleInjected) { + console.log("avatar, catch css delete"); + + DynamiCSS.removeStyleSheet(idAvatarStyles); + } + setIdAvatarStyles(""); + setStyleInjected(false); + } + }, []); + + React.useEffect(() => { + /* if (!borderRadius) { + DynamiCSS.removeStyleSheet(idAvatarStyles); + return; + } */ let idStyle: string = "avatar-styles"; const styleSheet: DynamicSheet = makeDynamicAvatarCSSRules(borderRadius); // check if classname was added @@ -50,18 +63,10 @@ export const useAvatarStyle = (borderRadius: string | undefined): boolean => { DynamiCSS.editStyleSheet(idAvatarStyles, styleSheet.sheetRules || []); } - return () => { - console.log("avatar, deleting init", styleInjected, idAvatarStyles); - if (styleInjected) { - console.log("avatar, catch css delete"); - DynamiCSS.removeStyleSheet(idAvatarStyles); - } - setIdAvatarStyles(""); - setStyleInjected(false); - } }, [borderRadius]); + /* React.useEffect(() => { return () => { diff --git a/src/files-ui/components/dropzone/components/dropzone/Dropzone.tsx b/src/files-ui/components/dropzone/components/dropzone/Dropzone.tsx index ca99d18e3a7678189ea696163d92513f4435ad29..ecdf8d319deddfcdd262ae41f82adf4d806d7c30 100644 --- a/src/files-ui/components/dropzone/components/dropzone/Dropzone.tsx +++ b/src/files-ui/components/dropzone/components/dropzone/Dropzone.tsx @@ -19,7 +19,7 @@ import { UploadResponse, instantPreparingToUploadOne, fakeFuiUpload, - uploadOnePromiseXHR, + uploadExtFile, sleepTransition, toUploadableExtFileList, cleanInput, @@ -272,24 +272,41 @@ const Dropzone: React.FC<DropzoneProps> = (props: DropzoneProps) => { //UPLOADING => UPLOAD() //upload one file and notify about change - const uploadResponse: UploadResponse = fakeUpload - ? await fakeFuiUpload(currentExtFileInstance, DropzoneLocalizer) - : await uploadOnePromiseXHR( - currentExtFileInstance, - url, - method, - headers, - uploadLabel - ); + let uploadResponse: UploadResponse; + try { + uploadResponse = fakeUpload + ? await fakeFuiUpload(currentExtFileInstance, DropzoneLocalizer) + : await uploadExtFile( + currentExtFileInstance, + url, + method, + headers, + uploadLabel + ); + } catch (error) { + uploadResponse = { + id: currentExtFileInstance.id, + serverResponse: { + success: false, + message: "Error on upload: unexpected error " + error, + payload: {}, + }, + uploadedFile: { ...currentExtFileInstance }, + }; + } const { uploadedFile } = uploadResponse; //update instances currentExtFileInstance.uploadStatus = uploadedFile.uploadStatus; currentExtFileInstance.uploadMessage = uploadedFile.uploadMessage; - + //add fake progress only on fakeupload if (fakeUpload) { - console.log("Adding fake progress", fakeUpload, uploadedFile.progress); + console.log( + "Adding fake progress", + fakeUpload, + uploadedFile.progress + ); currentExtFileInstance.progress = uploadedFile.progress; } //CHANGE @@ -526,10 +543,10 @@ const Dropzone: React.FC<DropzoneProps> = (props: DropzoneProps) => { console.log("validatedFuiFileList pre", fuiFileListToValidate); let finalNumberOfValids: number = numberOfValidFiles; - if (behaviour === "replace") { + if (behaviour === "replace") { //re-start number of valids finalNumberOfValids = 0; - } + } const validatedFuiFileList: ExtFile[] = validateExtFileList( fuiFileListToValidate, diff --git a/src/files-ui/components/file-mosaic/components/file-mosaic/FileMosaic.tsx b/src/files-ui/components/file-mosaic/components/file-mosaic/FileMosaic.tsx index e56721000b31b7e9454d2efcaac3391d31155e25..8636799c8bacef7fb13e0bb24c879635c9e9edac 100644 --- a/src/files-ui/components/file-mosaic/components/file-mosaic/FileMosaic.tsx +++ b/src/files-ui/components/file-mosaic/components/file-mosaic/FileMosaic.tsx @@ -9,7 +9,6 @@ import FileMosaicName from "../FileMosaicName/FileMosaicName"; import FileMosaicUploadLayer from "../FileMosaicUploadLayer/FileMosaicUploadLayer"; import useFileMosaicInitializer from "../../hooks/useFileMosaicInitializer"; import FileMosaicImageLayer from "../FIleMosaicImageLayer/FileMosaicImageLayer"; -import getProgress from "../../hooks/getProgress"; import { useIsUploading } from "../../hooks/useIsUploading"; import { Tooltip } from "../../../tooltip"; import FileMosaicMainLayer from "../FileMosaicMainLayer.tsx/FileMosaicMainLayer"; diff --git a/src/files-ui/components/icons/IconProps/IconProps.ts b/src/files-ui/components/icons/IconProps/IconProps.ts index 56bdb6dc878ec9b238d02215486c679bd795ddc0..3c6fe21cb002b3f67760fa4a8cebb9b918a0ae2d 100644 --- a/src/files-ui/components/icons/IconProps/IconProps.ts +++ b/src/files-ui/components/icons/IconProps/IconProps.ts @@ -1,7 +1,7 @@ import { CSSProperties } from "react"; export interface IconProps { - size?: "micro" | "small" | "semi-medium" | "medium" | "large" | number; + size?: "micro" | "small" | "semi-medium" | "medium" | "large"| "extra-large" | number; /** * main color for icon */ diff --git a/src/files-ui/components/icons/utils/utils.ts b/src/files-ui/components/icons/utils/utils.ts index 0676af4ac868683351cf37d71672f18d3864bfb1..0559dca7dc467c971263c6d7b350d4935876d265 100644 --- a/src/files-ui/components/icons/utils/utils.ts +++ b/src/files-ui/components/icons/utils/utils.ts @@ -19,6 +19,8 @@ export const parseSize = (sizeStr: IconProps["size"] | number): number => { return 25; case "large": return 28; + case "extra-large": + return 32; default: return 24; } diff --git a/src/files-ui/components/index.ts b/src/files-ui/components/index.ts index fad03ef4e7ab86e50d4bac95958a6cae30de32a4..010e67fb2b887a5d7ee3998edb6ed181b2a742bb 100644 --- a/src/files-ui/components/index.ts +++ b/src/files-ui/components/index.ts @@ -1,3 +1,6 @@ +export { Avatar } from "./avatar"; +export * from "./avatar"; + export { Dropzone } from "./dropzone"; export * from "./dropzone"; diff --git a/src/files-ui/components/loader/LoaderContainer/LoaderContainerProps.ts b/src/files-ui/components/loader/LoaderContainer/LoaderContainerProps.ts index 22c71e0981df8ecba3c5db988502ebab22c4c505..20ef4fb9940a952330d2984c3c049813fcc344d3 100644 --- a/src/files-ui/components/loader/LoaderContainer/LoaderContainerProps.ts +++ b/src/files-ui/components/loader/LoaderContainer/LoaderContainerProps.ts @@ -1,7 +1,7 @@ import { OverridableComponentProps } from "../../overridable"; export interface LoaderContainerPropsMap extends OverridableComponentProps { - size?: "micro" | "small" | "semi-medium" | "medium" | "large" | number; + size?: "micro" | "small" | "semi-medium" | "medium" | "large"| "extra-large" | number; onClick?: Function; text?:string; } diff --git a/src/files-ui/components/previews/FullScreen/FullScreen.scss b/src/files-ui/components/previews/FullScreen/FullScreen.scss index 584d77b0591deee1caf96105425a1cb4a8b41591..727ca5036bb2977b03f2dec504f932f022e0d8f1 100644 --- a/src/files-ui/components/previews/FullScreen/FullScreen.scss +++ b/src/files-ui/components/previews/FullScreen/FullScreen.scss @@ -4,7 +4,7 @@ align-items: center; justify-content: center; width: 100%; - height: 100%; + height: 100vh; top: 0; left: 0; background: rgba(0, 0, 0, 0.734); @@ -15,29 +15,46 @@ transform: translate(0); } z-index: 4; + box-sizing: border-box; + //padding: 10px 50px; } .fui-fullscreen-relative-container { position: relative; - //overflow: hidden; - height: 80%; - //width: 60%; - width: 80%; + width: 90%; + height: 90%; + overflow: hidden; display: flex; align-items: center; justify-content: center; + img{ + height: 100%; + width: auto; + } + video { + height: 100%; + width: auto; + } /* @media (max-width: 600px) { width: 80%; height: auto; - } + }*/ @media (max-width: 960px) { - width: 90%; - height: auto; - } */ + height: 90%; + width: 100%; + video { + height: auto; + width: 100%; + } + img{ + height: auto; + width: 100%; + } + } } .button-full-screen { + position: absolute; top: 0; right: 0; - position: absolute; } diff --git a/src/files-ui/components/previews/FullScreen/FullScreen.tsx b/src/files-ui/components/previews/FullScreen/FullScreen.tsx index 67d259f18f2cac7f393639defa1cf7d4dbfd3648..4cc9b0fbfa49a59a356e45fe1e8b6e884c957a3a 100644 --- a/src/files-ui/components/previews/FullScreen/FullScreen.tsx +++ b/src/files-ui/components/previews/FullScreen/FullScreen.tsx @@ -1,9 +1,8 @@ import * as React from "react"; -import { Cancel } from "../../icons"; +import { Clear } from "../../icons"; import { FullScreenProps } from "./FullScreenProps"; import "./FullScreen.scss"; const FullScreen: React.FC<FullScreenProps> = (props: FullScreenProps) => { - const { open, onClose, children } = props; function handleClose<T extends HTMLDivElement>( @@ -24,21 +23,20 @@ const FullScreen: React.FC<FullScreenProps> = (props: FullScreenProps) => { {open && ( <div className="fui-fullscreen-relative-container" - onClick={(evt) => { - evt.preventDefault(); - }} + onClick={handleClose} > {children} - {onClose && ( - <Cancel - color="rgba(255,255,255,0.8)" - onClick={handleClose} - colorFill="black" - className="button-full-screen" - /> - )} </div> )} + {onClose && ( + <Clear + color="rgba(255,255,255,0.8)" + onClick={handleClose} + colorFill="transparent" + className="button-full-screen" + size={"extra-large"} + /> + )} </div> ); }; diff --git a/src/files-ui/components/previews/ImagePreview/ImagePreview.tsx b/src/files-ui/components/previews/ImagePreview/ImagePreview.tsx index 354aef6a382b2aba37536b3c29bac85a91684485..a7761daba907f00097540b43d06efdfeff55b7f7 100644 --- a/src/files-ui/components/previews/ImagePreview/ImagePreview.tsx +++ b/src/files-ui/components/previews/ImagePreview/ImagePreview.tsx @@ -11,10 +11,8 @@ import "./ImagePreview.scss"; const ImagePreview: React.FC<ImagePreviewProps> = ( props: ImagePreviewProps ) => { - const { src, alt, className, style, width, height, onError } = mergeProps( - props, - ImagePreviewDefaultProps - ); + const { src, alt, className, style, width, height, onError, smart } = + mergeProps(props, ImagePreviewDefaultProps); //console.table({ src, alt, className, style, width, height }); const [source, setSource] = React.useState<string | undefined>(undefined); @@ -26,15 +24,22 @@ const ImagePreview: React.FC<ImagePreviewProps> = ( const newImageSrc: string | undefined = await readAsDataURL(src); handleSetStrSource(newImageSrc); }; + const handleSetStrSource = async (imageSource: string | undefined) => { - if (imageSource) { - const orientation: "landscape" | "portrait" = await getImageOrientation( - imageSource - ); - setOrientation(orientation); - } + if (imageSource === "" || !imageSource) return; + + setSource(imageSource); + + if (!smart) return; + + const orientation: "landscape" | "portrait" = await getImageOrientation( + imageSource + ); + setOrientation(orientation); + setSource(imageSource); }; + React.useEffect(() => { //if not undefined if (!src) { @@ -58,14 +63,16 @@ const ImagePreview: React.FC<ImagePreviewProps> = ( //console.log("ImagePreview", src, source); const finalWidth: string | number | undefined = - width || (orientation === "landscape" ? "100%" : undefined); + width || (orientation === "landscape" && smart ? "100%" : undefined); const finalHeight: string | number | undefined = - height || (orientation === "portrait" ? "100%" : undefined); - - const handleError=(evt: React.SyntheticEvent<HTMLImageElement, Event>)=>{ - console.log("handleError", onError); - onError?.(evt); - } + height || (orientation === "portrait" && smart ? "100%" : undefined); + + console.log("Image result", finalHeight, finalWidth, orientation, smart); + const handleError = (evt: React.SyntheticEvent<HTMLImageElement, Event>) => { + console.log("handleError", onError); + onError?.(evt); + }; + return ( <React.Fragment> {src && source && ( diff --git a/src/files-ui/components/previews/ImagePreview/ImagePreviewProps.ts b/src/files-ui/components/previews/ImagePreview/ImagePreviewProps.ts index dbcc9247e3ebb8f6300b3e4e0024955615ea7719..f008f694a6faf3234511059de8874238f0cc59ee 100644 --- a/src/files-ui/components/previews/ImagePreview/ImagePreviewProps.ts +++ b/src/files-ui/components/previews/ImagePreview/ImagePreviewProps.ts @@ -25,6 +25,12 @@ export interface ImagePreviewProps extends OverridableComponentProps { * Fallback when the image is not loaded correctly */ onError?: React.ReactEventHandler<HTMLImageElement> | undefined; + /** + * If true, images will be analized and showed according their orientation + * orientation can be landscape if height < width. + * In that case height will be set to 100%. Otherwise width will be set to 100% + */ + smart?: boolean; } export const ImagePreviewDefaultProps: ImagePreviewProps = { @@ -32,4 +38,5 @@ export const ImagePreviewDefaultProps: ImagePreviewProps = { //height: "100%", alt: "image-preview", //className: "fui-image-preview" + smart:true } \ No newline at end of file diff --git a/src/files-ui/core/index.ts b/src/files-ui/core/index.ts index b4651cefbfddab2cd265e3ed356edd25854b6f42..aea53dc9a7e2a446ce5d09369fc5b3f0ea69aa97 100644 --- a/src/files-ui/core/index.ts +++ b/src/files-ui/core/index.ts @@ -96,7 +96,7 @@ export { } from "./types" export { - FilesUIUpload, uploadPromiseXHR, + uploadExtFile, FuiUpload, completeUploadResult, instantPreparingToUploadOne, @@ -104,8 +104,20 @@ export { sleepTransition, toUploadableExtFileList, unableToUploadResult, - unexpectedErrorUploadResult, uploadOnePromiseXHR, + makeServerResponse, + uploadFile, + uploadFormData, + ABORTED_ERROR_RESPONSE, + JSON_PARSE_ERROR_RESPONSE, + JsonParseResponse, + NO_XHR_PROVIDED_ERROR, + TIMEOUT_ERROR_RESPONSE, + UNEXPECTED_ERROR_RESPONSE, + makeErrorUploadResponse, + makeSuccessUploadResponse, + addExtraData, + addHeaders } from "./upload"; export { @@ -139,7 +151,7 @@ export { } from "./validation"; -export { createFuiRippleFromDiv,createRippleButton } from "./ripple"; +export { createFuiRippleFromDiv, createRippleButton } from "./ripple"; export { asureColor, diff --git a/src/files-ui/core/upload/addExtraData.upload.ts b/src/files-ui/core/upload/addExtraData.upload.ts new file mode 100644 index 0000000000000000000000000000000000000000..40c5135e216abfc12a18dc2de4cba7ca36060da6 --- /dev/null +++ b/src/files-ui/core/upload/addExtraData.upload.ts @@ -0,0 +1,17 @@ +export default function ( + formData: FormData, + extraData: Record<string, string> | undefined +) { + //headers + const extraDataKeys: string[] = Object.keys(extraData || {}); + //const headerValues: string[] = Object.values(headers); + for (let i = 0; i < extraDataKeys.length && extraData; i++) { + console.log("uploadFile extraData", extraDataKeys[i], extraData[extraDataKeys[i]]); + + formData.append(extraDataKeys[i], extraData[extraDataKeys[i]]); + + } + + formData.append("otherValue", "HAAAAAAAAAAAAAAa"); + +} \ No newline at end of file diff --git a/src/files-ui/core/upload/addheaders.upload.ts b/src/files-ui/core/upload/addheaders.upload.ts new file mode 100644 index 0000000000000000000000000000000000000000..2ba05b769b8927862169e1a10d6ead6b2dd15496 --- /dev/null +++ b/src/files-ui/core/upload/addheaders.upload.ts @@ -0,0 +1,17 @@ +export default function addHeaders( + xhr: XMLHttpRequest, + headers: Record<string, string> | undefined +) { + //headers + const headerKeys: string[] = Object.keys(headers || {}); + //const headerValues: string[] = Object.values(headers); + for (let i = 0; i < headerKeys.length && headers; i++) { + console.log("uploadFile headers", headerKeys[i], headers[headerKeys[i]]); + xhr.setRequestHeader( + headerKeys[i], + headers[headerKeys[i]] + ); + } + + +} \ No newline at end of file diff --git a/src/files-ui/core/upload/errors.upload.ts b/src/files-ui/core/upload/errors.upload.ts new file mode 100644 index 0000000000000000000000000000000000000000..d4b3b00b7dfe16cc22d9acf106a3ea1a635ac6e4 --- /dev/null +++ b/src/files-ui/core/upload/errors.upload.ts @@ -0,0 +1,37 @@ +import { ExtFile, UploadResponse } from "../types"; + +export const TIMEOUT_ERROR_RESPONSE = { + success: false, + message: "Timeout error", + payload: {} +}; +export const ABORTED_ERROR_RESPONSE = { + success: false, + message: "Upload aborted", + payload: {} +} +export const JSON_PARSE_ERROR_RESPONSE = { + success: false, + message: "Error when parsing JSON response", + payload: {} +} + +export const UNEXPECTED_ERROR_RESPONSE = { + success: false, + message: "Unexpected error", + payload: {} +} + +export const NO_XHR_PROVIDED_ERROR = (extFile: ExtFile): UploadResponse => { + return { + uploadedFile: + { + ...extFile, + uploadMessage: "Unable to upload. xhr object was not provided", + uploadStatus: "error" + }, + + id: extFile.id, + serverResponse: {} + } +} \ No newline at end of file diff --git a/src/files-ui/core/upload/index.ts b/src/files-ui/core/upload/index.ts index 515c08747b197779f75d88500b4c3cf9aeeae9ed..9977205eba298f77fd98096128c871052d241397 100644 --- a/src/files-ui/core/upload/index.ts +++ b/src/files-ui/core/upload/index.ts @@ -1,15 +1,36 @@ export { - FilesUIUpload, uploadPromiseXHR, + + uploadExtFile, FuiUpload, completeUploadResult, + unableToUploadResult, + uploadOnePromiseXHR, + uploadFile, + uploadFormData, +} from "./upload"; +export { + ABORTED_ERROR_RESPONSE, + JSON_PARSE_ERROR_RESPONSE, + NO_XHR_PROVIDED_ERROR, + TIMEOUT_ERROR_RESPONSE, + UNEXPECTED_ERROR_RESPONSE, +} from "./errors.upload"; +export { + JsonParseResponse, + makeErrorUploadResponse, + makeServerResponse, + makeSuccessUploadResponse, +} from "./response.upload"; + +export { default as addExtraData } from "./addExtraData.upload"; +export { default as addHeaders } from "./addheaders.upload"; + +export { instantPreparingToUploadOne, preparingToUploadOne, sleepTransition, toUploadableExtFileList, - unableToUploadResult, - unexpectedErrorUploadResult, - uploadOnePromiseXHR, -} from "./upload"; +} from "./utils.upload"; /* export { FuiUpload, completeUploadResult, diff --git a/src/files-ui/core/upload/response.upload.ts b/src/files-ui/core/upload/response.upload.ts new file mode 100644 index 0000000000000000000000000000000000000000..047b24a211f01a0770e3d1f79d7d6f2dbf14fec6 --- /dev/null +++ b/src/files-ui/core/upload/response.upload.ts @@ -0,0 +1,61 @@ +import { ExtFile, ServerResponse, UploadResponse } from "../types"; +import { JSON_PARSE_ERROR_RESPONSE } from "./errors.upload"; + +export const makeServerResponse = (success: any, message: string, payload: any): ServerResponse => { + const result: ServerResponse = { success: success, message: message, payload: payload } as ServerResponse; + return result; +} +export const JsonParseResponse = (xhr: XMLHttpRequest): ServerResponse => { + try { + const jsonResponse = JSON.parse(xhr.response); + const success: any = jsonResponse.success; + const message: string = jsonResponse.message; + const payload: any = jsonResponse.payload; + + const fuiResponse: ServerResponse = { + success: typeof success === "boolean" ? success : false, + message: typeof message === "string" ? message : "Error on message response", + payload: payload || {} + } + return fuiResponse + } catch (error) { + console.log("FuiUpload ERROR", error); + return JSON_PARSE_ERROR_RESPONSE; + } +} + + + +export const makeSuccessUploadResponse = ( + extFile: ExtFile, + responseFui: ServerResponse +): UploadResponse => { + return { + id: extFile.id, + serverResponse: responseFui, + uploadedFile: + { + ...extFile, + uploadMessage: responseFui.message, + uploadStatus: "success" + }, + } +} + + +export const makeErrorUploadResponse = ( + extFile: ExtFile, + responseFui: ServerResponse +): UploadResponse => { + return { + id: extFile.id, + serverResponse: responseFui, + uploadedFile: + { + ...extFile, + uploadMessage: responseFui.message, + uploadStatus: "error" + }, + } +} + diff --git a/src/files-ui/core/upload/upload.ts b/src/files-ui/core/upload/upload.ts index 9d619bb35cbac14adec6ce72a635b877b7001f7a..8a3c7435ad1a700ebebac56178e762954b068d2b 100644 --- a/src/files-ui/core/upload/upload.ts +++ b/src/files-ui/core/upload/upload.ts @@ -1,106 +1,11 @@ import { ExtFile, ExtFileInstance, Method, UPLOADSTATUS } from "../types"; import { ServerResponse, UploadResponse } from "../types/uploadTypes"; -export const makeServerResponse = (success: boolean, message: string, payload: any): ServerResponse => { - const result: ServerResponse = { success: success, message: message, payload: payload } as ServerResponse; - return result; -} -export function uploadFile( - file: File, - url: string, - method?: Method, - label?: string, - headers?: Record<string, string> -): Promise<ServerResponse> { - return new Promise((resolve, reject) => { - let uploadResult: ServerResponse = makeServerResponse(false, "", {}); - const finalMethod: string = method && ["POST", "PUT", "PATCH"].includes(method.toLocaleLowerCase()) ? method : "POST"; - - //XMLHttpRequest Object - const xhr: XMLHttpRequest = new XMLHttpRequest(); - xhr.upload.onload = () => { - console.log("uploadFile onLoad", xhr.readyState, xhr.response); - }; - xhr.upload.ontimeout = () => { - uploadResult = makeServerResponse(false, "Timeout error", {}); - resolve(uploadResult); - }; - xhr.upload.onabort = () => { - uploadResult = makeServerResponse(false, "Upload aborted", {}); - resolve(uploadResult); - }; - xhr.onreadystatechange = async (e) => { - console.log("uploadFile onreadystatechange", xhr.readyState, xhr.response); - if (xhr.readyState === 4 && xhr.response !== "") { - let fuiServerRes: ServerResponse; - try { - const jsonResponse = JSON.parse(xhr.response); - const success: boolean = jsonResponse.success; - const message: string = jsonResponse.message; - const payload: any = jsonResponse.payload; - - console.log("uploadFile ====> status", success); - console.log("uploadFile ====> message", message); - console.log("uploadFile ====> payload", payload); - - fuiServerRes = { - success: typeof success === "boolean" ? success : false, - message: typeof message === "string" ? message : "Error on response", - payload: payload || {} - } - resolve(fuiServerRes); - } catch (error) { - fuiServerRes = { - success: false, - message: "Unexpected error: " + error, - payload: {} - } - console.log("uploadFile ERROR", error); - resolve(fuiServerRes); - } - } else { - console.log("uploadFile Naranjas Changed: ", xhr.readyState, xhr.response); - } - - } - // open request - - xhr.open(finalMethod, url, true); - - //headers - const headerKeys: string[] = Object.keys(headers || {}); - //const headerValues: string[] = Object.values(headers); - for (let i = 0; i < headerKeys.length && headers; i++) { - console.log("uploadFile headers", headerKeys[i], headers[headerKeys[i]]); - xhr.setRequestHeader( - headerKeys[i], - headers[headerKeys[i]] - ); - } - - //start uploading - const formData = new FormData(); - formData.append(label || "file", file); - xhr.send(formData); - }); - - -} -export function uploadFormData( - file: File, - url: string, - method?: Method, - label?: string, - headers?: Record<string, string> -): Promise<ServerResponse> { - return new Promise((resolve, reject) => { - let uploadResult: ServerResponse = { success: false, message: "", payload: {} }; +import addExtraDataUpload from "./addExtraData.upload"; +import addHeaders from "./addheaders.upload"; +import { ABORTED_ERROR_RESPONSE, NO_XHR_PROVIDED_ERROR, TIMEOUT_ERROR_RESPONSE, UNEXPECTED_ERROR_RESPONSE } from "./errors.upload"; +import { JsonParseResponse, makeErrorUploadResponse, makeServerResponse, makeSuccessUploadResponse } from "./response.upload"; - - resolve(uploadResult); - }); -} - /** * Uploads one formData object to a given endpoint in a promisified way * @param xhr XMLHTTPrequest object @@ -110,85 +15,45 @@ export function uploadFormData( * @param headers the set of headers * @returns a server response that consists on {status, payload, message} */ -export const FilesUIUpload = ( +export const uploadFormData = ( xhr: XMLHttpRequest, - method: Method, + method: Method | undefined = "POST", endpoint: string, data: FormData, - headers: Record<string, string> + headers: Record<string, string> | undefined ) => { return new Promise<ServerResponse>((resolve, reject) => { console.log("uploadFile", xhr, method, endpoint, data, headers); + const finalMethod: Method = ["POST", "PUT", "PATCH"].includes(method.toUpperCase()) ? method : "POST"; + xhr.upload.onload = () => { console.log("uploadFile onLoad", xhr.readyState, xhr.response); }; - xhr.upload.ontimeout = () => { - //onError("Timeout error"); - resolve( - { - success: false, - message: "Timeout error", - payload: {} - } - ); - }; - - xhr.upload.onabort = () => { - resolve( - { - success: false, - message: "Upload aborted", - payload: {} - } - ); - }; + xhr.upload.ontimeout = () => resolve(TIMEOUT_ERROR_RESPONSE); + xhr.upload.onabort = () => resolve(ABORTED_ERROR_RESPONSE); // listen for `progress` event //currently listening on FileItem component hook xhr.onreadystatechange = async (e) => { //console.log("Finished", xhr); console.log("uploadFile onreadystatechange", xhr.readyState, xhr.response); - if (xhr.readyState === 4 && xhr.response !== "") { - let fuiServerRes: ServerResponse; - try { - const jsonResponse = JSON.parse(xhr.response); - const success: any = jsonResponse.success; - const message: string = jsonResponse.message; - const payload: any = jsonResponse.payload; - console.log("uploadFile ====> status", success); - console.log("uploadFile ====> message", message); - console.log("uploadFile ====> payload", payload); - - fuiServerRes = { - success: typeof success === "boolean" ? success : false, - message: typeof message === "string" ? message : "Error on response", - payload: payload || {} - } - resolve(fuiServerRes); - } catch (error) { - fuiServerRes = { - success: false, - message: "Unexpected error", - payload: {} - } - console.log("uploadFile ERROR", error); - resolve(fuiServerRes); + if (xhr.readyState === 4) { + if (xhr.response !== "") { + //there is th answer + resolve(JsonParseResponse(xhr)); + } else { + //error unexpected + resolve(UNEXPECTED_ERROR_RESPONSE); } } else { - console.log("uploadFile Naranjas Changed to " + xhr.readyState); + console.log("FuiUpload NOT YET" + xhr.readyState); } }; // open request - xhr.open(method, endpoint, true); - const headerKeys: string[] = Object.keys(headers); - //const headerValues: string[] = Object.values(headers); - for (let i = 0; i < headerKeys.length; i++) { - console.log("uploadFile FuiUpload headers", headerKeys[i], headers[headerKeys[i]]); - xhr.setRequestHeader( - headerKeys[i], - headers[headerKeys[i]] - ); - } + xhr.open(finalMethod, endpoint, true); + + //add header to request + addHeaders(xhr, headers); //start uploading xhr.send(data); }); @@ -203,128 +68,90 @@ export const FilesUIUpload = ( * @param headers headers for request * @returns */ -export const uploadPromiseXHR = async ( - file: ExtFile, +export const uploadExtFile = async ( + extFile: ExtFile, url: string, - method: Method, - headers?: Record<string, string> + method?: Method, + headers?: Record<string, string>, + uploadLabel?: string, ): Promise<UploadResponse> => { return new Promise(async (resolve, reject) => { try { - const uploader: XMLHttpRequest | undefined = file.xhr; + const uploader: XMLHttpRequest | undefined = extFile.xhr; + if (!uploader) { - resolve( - { - uploadedFile: - { - ...file, - uploadMessage: "Unable to upload. xhr object was not provided", - uploadStatus: "error" - }, - - id: file.id, - serverResponse: {} - - } - ); + resolve(NO_XHR_PROVIDED_ERROR(extFile)); return; } const localMethod: Method = method || "POST"; - - const fileToUpload: File = file.file as File; + const fileToUpload: File = extFile.file as File; const formData = new FormData(); - formData.append("file", fileToUpload); - formData.append("otherValue", "HAAAAAAAAAAAAAAa"); + formData.append(uploadLabel || "file", fileToUpload); + // add extra data to upload + const finalExtraData: Record<string, any> = + { otherValue: "other valueee haaaa", param2: { tecnica: "KIKOHUUUU", friend: "Chaos", age: 25 }, ...extFile.extraUploadData }; + + addExtraDataUpload(formData, finalExtraData); console.log("FORMDATA", formData); + let responseFui: ServerResponse; - //stablish events - responseFui = await FilesUIUpload( + responseFui = await uploadFormData( uploader, localMethod, url, formData, headers || {}); - if (responseFui.success) { // status is true - resolve( - { - id: file.id, - serverResponse: responseFui, - uploadedFile: - { - ...file, - uploadMessage: responseFui.message, - uploadStatus: "success" - }, - - - } - - ); + resolve(makeSuccessUploadResponse(extFile, responseFui)); } else { // status is false - resolve( - { - id: file.id, - serverResponse: responseFui, - uploadedFile: - { - ...file, - uploadMessage: responseFui.message, - uploadStatus: "error" - }, - - - } - ); + resolve(makeErrorUploadResponse(extFile, responseFui)); } } catch (error) { // on error console.log("uploadPromiseXHR uploadPromiseXHR ERROR", error); resolve( - { - id: file.id, - serverResponse: {}, - uploadedFile: - { - ...file, - uploadMessage: "Unexpected error", - uploadStatus: "error" - }, - - - - } + makeErrorUploadResponse(extFile, UNEXPECTED_ERROR_RESPONSE) ); } }); }; -/// refactorizar, entregar solamente -///input: file o formData, url, method, headers y label on backend -// {payload, success, message:str} -export const unexpectedErrorUploadResult = (extFile: ExtFile): UploadResponse => { - return { - id: extFile.id, - uploadedFile: - { - ...extFile, - uploadMessage: "Unable to upload. xhr object was not provided", - uploadStatus: "error" - }, - serverResponse: { +export function uploadFile( + file: File, + url: string, + method?: Method, + label?: string, + headers?: Record<string, string> +): Promise<ServerResponse> { + return new Promise(async (resolve, reject) => { + + + //start uploading + const formData = new FormData(); + + formData.append(label || "file", file); + + try { + const serverResponse: ServerResponse = await uploadFormData(new XMLHttpRequest(), method, url, formData, headers); + resolve(serverResponse); + } catch (error) { + // on error + console.log("uploadPromiseXHR uploadPromiseXHR ERROR", error); + resolve(UNEXPECTED_ERROR_RESPONSE); } - } + }); } + export const unableToUploadResult = ( extFile: ExtFile ): UploadResponse => { @@ -339,6 +166,7 @@ export const unableToUploadResult = ( } } } + export const completeUploadResult = ( extFile: ExtFile, serverResponse: ServerResponse, @@ -354,6 +182,10 @@ export const completeUploadResult = ( serverResponse: serverResponse } } + +/** + * @deprecated + */ export const uploadOnePromiseXHR = async ( extFile: ExtFile, url: string, @@ -383,7 +215,9 @@ export const uploadOnePromiseXHR = async ( } else formData.append("file", fileToUpload); - const finalExtraData: Record<string, any> = { otherValue: "other valueee haaaa", param2: { tecnica: "KIKOHUUUU", friend: "Chaos", age: 25 } }; + const finalExtraData: Record<string, any> = + { otherValue: "other valueee haaaa", param2: { tecnica: "KIKOHUUUU", friend: "Chaos", age: 25 }, ...extraData }; + if (finalExtraData) { const extraDataKeys: string[] = Object.keys(finalExtraData); @@ -414,7 +248,9 @@ export const uploadOnePromiseXHR = async ( } }); }; + /** + * @deprecated * Uploads one formData object to a given endpoint in a promisified way * @param xhr XMLHTTPrequest object * @param method method for uploading @@ -435,112 +271,29 @@ export const FuiUpload = ( xhr.upload.onload = () => { console.log("FuiUpload onLoad", xhr.readyState, xhr.response); - }; - xhr.upload.ontimeout = () => { - //onError("Timeout error"); - resolve( - { - success: false, - message: "Timeout error", - payload: {} - } - ); - }; + xhr.upload.ontimeout = () => resolve(TIMEOUT_ERROR_RESPONSE); + xhr.upload.onabort = () => resolve(ABORTED_ERROR_RESPONSE); - xhr.upload.onabort = () => { - resolve( - { - success: false, - message: "Upload aborted", - payload: {} - } - ); - }; // listen for `progress` event - //currently listening on FileItem component hook + //currently listening on FileMosaic component hook + xhr.onreadystatechange = async (e) => { //console.log("Finished", xhr); console.log("FuiUpload onreadystatechange", xhr.readyState, xhr.response, xhr); - let duiRes = { - success: false, - message: "Unexpected error", - payload: {} - } + if (xhr.readyState === 4) { if (xhr.response !== "") { //there is th answer - let duiRes: ServerResponse; - try { - const jsonResponse = JSON.parse(xhr.response); - const success: any = jsonResponse.success; - const message: string = jsonResponse.message; - const payload: any = jsonResponse.payload; - - duiRes = { - success: typeof success === "boolean" ? success : false, - message: typeof message === "string" ? message : "Error on message response", - payload: payload || {} - } - resolve(duiRes); - } catch (error) { - duiRes = { - success: false, - message: "Error when parsing JSON response", - payload: {} - } - console.log("FuiUpload ERROR", error); - resolve(duiRes); - } + resolve(JsonParseResponse(xhr)); } else { //error unexpected - duiRes = { - success: false, - message: "Unexpected error", - payload: {} - } - resolve(duiRes); + resolve(UNEXPECTED_ERROR_RESPONSE); } } else { console.log("FuiUpload NOT YET" + xhr.readyState); } - - /* if (xhr.readyState === 4 && xhr.response !== "") { - let duiRes: ServerResponse; - try { - const jsonResponse = JSON.parse(xhr.response); - const success: any = jsonResponse.success; - const message: string = jsonResponse.message; - const payload: any = jsonResponse.payload; - console.log("FuiUpload ====> success", success); - console.log("FuiUpload ====> message", message); - console.log("FuiUpload====> payload", payload); - - duiRes = { - success: typeof success === "boolean" ? success : false, - message: typeof message === "string" ? message : "Error on response", - payload: payload || {} - } - resolve(duiRes); - } catch (error) { - duiRes = { - success: false, - message: "Unexpected error", - payload: {} - } - console.log("FuiUpload ERROR", error); - resolve(duiRes); - } - } else { - console.log("FuiUpload Naranjas Changed to " + xhr.readyState); - const duiRes = { - success: false, - message: "Unexpected error", - payload: {} - } - resolve(duiRes); - } */ }; // open request xhr.open(method, endpoint, true); @@ -558,75 +311,5 @@ export const FuiUpload = ( }); }; -/** - * Initializes the xhr attribute for performing uploads - * @param extFileList the list of extended files - * @returns the array of extFiles with the xhr attribute initialized - */ -export const toUploadableExtFileList = ( - extFileList: ExtFile[] | ExtFileInstance[] -): ExtFile[] => { - if (!extFileList) return []; - return extFileList.map(extFile => { - return { ...extFile, xhr: new XMLHttpRequest() } - }); -} -/** - * Updates the uploadStatus of the given extFile - * from "preparing" to "uploading" - * @param extFile the extended file - * @returns the extended file with uploadStatus updated to "uploading" - */ -export const instantPreparingToUploadOne = ( - extFile: ExtFileInstance | ExtFile -): ExtFileInstance | ExtFile => { - if (extFile.uploadStatus === "preparing") { - //for ExtFile instance - extFile.uploadStatus = "uploading"; - //for ExtFile type - return { - ...extFile, - uploadStatus: "uploading", - }; - } - return extFile; -}; - -/** - * - * @param extFile the extended file - * @returns - */ -export const preparingToUploadOne = ( - extFile: ExtFileInstance | ExtFile -): Promise<ExtFileInstance | ExtFile> => { - return new Promise((resolve, reject) => { - setTimeout(() => { - if (extFile.uploadStatus === "preparing") { - //for ExtFile instance - extFile.uploadStatus = "uploading"; - //for ExtFile type - resolve({ - ...extFile, - uploadStatus: "uploading", - }); - } else - resolve(extFile); - }, 1500); - }); -}; -/** - * Sleeps for 1200 miliseconds for showing a better transition - * on uploading - * @returns true is everything is ok - */ -export const sleepTransition = ( -): Promise<boolean> => { - return new Promise((resolve, reject) => { - setTimeout(() => { - resolve(true); - }, 1200); - }); -} diff --git a/src/files-ui/core/upload/upload.utils.ts b/src/files-ui/core/upload/upload.utils.ts deleted file mode 100644 index 2a648065cb09f573baf9937e394054c52b5b5c91..0000000000000000000000000000000000000000 --- a/src/files-ui/core/upload/upload.utils.ts +++ /dev/null @@ -1,253 +0,0 @@ -import { ExtFile, ExtFileInstance, Method, ServerResponse, UploadResponse, UPLOADSTATUS } from "../types" - -export const unexpectedErrorUploadResult = (extFile: ExtFile): UploadResponse => { - return { - id: extFile.id, - uploadedFile: - { - ...extFile, - uploadMessage: "Unable to upload. xhr object was not provided", - uploadStatus: "error" - }, - serverResponse: { - } - } -} -export const unableToUploadResult = ( - extFile: ExtFile -): UploadResponse => { - return { - id: extFile.id, - uploadedFile: { - ...extFile, - uploadMessage: "Unable to upload. XHR was not provided", - uploadStatus: "error" - }, - serverResponse: { - } - } -} -export const completeUploadResult = ( - extFile: ExtFile, - serverResponse: ServerResponse, - result: UPLOADSTATUS -): UploadResponse => { - return { - id: extFile.id, - uploadedFile: { - ...extFile, - uploadMessage: serverResponse.message, - uploadStatus: result - }, - serverResponse: serverResponse - } -} -export const uploadOnePromiseXHR = async ( - extFile: ExtFile, - url: string, - method?: Method, - headers?: Record<string, string>, - uploadLabel?: string -): Promise<UploadResponse> => { - return new Promise(async (resolve, reject) => { - try { - const uploader: XMLHttpRequest | undefined = extFile.xhr; - if (!uploader) { - const duiUploadResponse: UploadResponse = unableToUploadResult(extFile); - resolve(duiUploadResponse); - return; - } - const localMethod: Method = (method) || "POST"; - const fileToUpload: File = extFile.file as File; - - const formData = new FormData(); - if (typeof uploadLabel === "string" && uploadLabel.length > 0) - formData.append(uploadLabel, fileToUpload); - else - formData.append("file", fileToUpload); - - let serverResponse: ServerResponse; - //stablish events - serverResponse = await FuiUpload(uploader, localMethod, url, formData, headers || {}); - - if (serverResponse.success) { - const duiUploadResponse: UploadResponse = completeUploadResult(extFile, serverResponse, "success"); - resolve(duiUploadResponse); - } else { - // success is false - const duiUploadResponse: UploadResponse = completeUploadResult(extFile, serverResponse, "error"); - resolve(duiUploadResponse); - } - } catch (error) { - // on error - console.log("ERROR", error); - const duiUploadResponse: UploadResponse = unableToUploadResult(extFile); - resolve(duiUploadResponse); - } - }); -}; -/** - * Uploads one formData object to a given endpoint in a promisified way - * @param xhr XMLHTTPrequest object - * @param method method for uploading - * @param endpoint endpoint to upload the file - * @param data FromData object to perform multipart form data - * @param headers the set of headers - * @returns a dui server response that consists on {success, payload, message} - */ -export const FuiUpload = ( - xhr: XMLHttpRequest, - method: Method, - endpoint: string, - data: FormData, - headers: Record<string, string> -) => { - return new Promise<ServerResponse>((resolve, reject) => { - console.log("DuiUpload", xhr, method, endpoint, data, headers); - xhr.upload.onload = () => { - console.log("DuiUpload onLoad", xhr.readyState, xhr.response); - - }; - - xhr.upload.ontimeout = () => { - //onError("Timeout error"); - resolve( - { - success: false, - message: "Timeout error", - payload: {} - } - ); - }; - - xhr.upload.onabort = () => { - resolve( - { - success: false, - message: "Upload aborted", - payload: {} - } - ); - }; - // listen for `progress` event - //currently listening on FileItem component hook - xhr.onreadystatechange = async (e) => { - //console.log("Finished", xhr); - console.log("DuiUpload onreadystatechange", xhr.readyState, xhr.response); - if (xhr.readyState === 4 && xhr.response !== "") { - let duiRes: ServerResponse; - try { - const jsonResponse = JSON.parse(xhr.response); - const success: any = jsonResponse.success; - const message: string = jsonResponse.message; - const payload: any = jsonResponse.payload; - console.log("====> success", success); - console.log("====> message", message); - console.log("====> payload", payload); - - duiRes = { - success: typeof success === "boolean" ? success : false, - message: typeof message === "string" ? message : "Error on response", - payload: payload || {} - } - resolve(duiRes); - } catch (error) { - duiRes = { - success: false, - message: "Unexpected error", - payload: {} - } - console.log("DuiUpload ERROR", error); - resolve(duiRes); - } - } else { - console.log("Naranjas Changed to " + xhr.readyState); - } - }; - // open request - xhr.open(method, endpoint, true); - const headerKeys: string[] = Object.keys(headers); - //const headerValues: string[] = Object.values(headers); - for (let i = 0; i < headerKeys.length; i++) { - console.log("DuiUpload headers", headerKeys[i], headers[headerKeys[i]]); - xhr.setRequestHeader( - headerKeys[i], - headers[headerKeys[i]] - ); - } - //start uploading - xhr.send(data); - }); - -}; -/** - * Initializes the xhr attribute for performing uploads - * @param extFileList the list of extended files - * @returns the array of extFiles with the xhr attribute initialized - */ -export const toUploadableExtFileList = ( - extFileList: ExtFile[] | ExtFileInstance[] - ): ExtFile[] => { - if (!extFileList) return []; - return extFileList.map(extFile => { - return { ...extFile, xhr: new XMLHttpRequest() } - }); -} - -/** - * Updates the uploadStatus of the given extFile - * from "preparing" to "uploading" - * @param extFile the extended file - * @returns the extended file with uploadStatus updated to "uploading" - */ -export const instantPreparingToUploadOne = ( - extFile: ExtFileInstance | ExtFile -): ExtFileInstance | ExtFile => { - if (extFile.uploadStatus === "preparing") { - //for ExtFile instance - extFile.uploadStatus = "uploading"; - //for ExtFile type - return { - ...extFile, - uploadStatus: "uploading", - }; - } - return extFile; -}; - -/** - * - * @param extFile the extended file - * @returns - */ -export const preparingToUploadOne = ( - extFile: ExtFileInstance | ExtFile -): Promise<ExtFileInstance | ExtFile> => { - return new Promise((resolve, reject) => { - setTimeout(() => { - if (extFile.uploadStatus === "preparing") { - //for ExtFile instance - extFile.uploadStatus = "uploading"; - //for ExtFile type - resolve({ - ...extFile, - uploadStatus: "uploading", - }); - } else - resolve(extFile); - }, 1500); - }); -}; -/** - * Sleeps for 1200 miliseconds for showing a better transition - * on uploading - * @returns true is everything is ok - */ -export const sleepTransition = ( -): Promise<boolean> => { - return new Promise((resolve, reject) => { - setTimeout(() => { - resolve(true); - }, 1200); - }); -} \ No newline at end of file diff --git a/src/files-ui/core/upload/utils.upload.ts b/src/files-ui/core/upload/utils.upload.ts new file mode 100644 index 0000000000000000000000000000000000000000..b117684745a3f62151ad6b5a1005d16b2381a2b6 --- /dev/null +++ b/src/files-ui/core/upload/utils.upload.ts @@ -0,0 +1,117 @@ +import { ExtFile, ExtFileInstance, Method, ServerResponse, UploadResponse, UPLOADSTATUS } from "../types" + +export const unexpectedErrorUploadResult = (extFile: ExtFile): UploadResponse => { + return { + id: extFile.id, + uploadedFile: + { + ...extFile, + uploadMessage: "Unable to upload. xhr object was not provided", + uploadStatus: "error" + }, + serverResponse: { + } + } +} +export const unableToUploadResult = ( + extFile: ExtFile +): UploadResponse => { + return { + id: extFile.id, + uploadedFile: { + ...extFile, + uploadMessage: "Unable to upload. XHR was not provided", + uploadStatus: "error" + }, + serverResponse: { + } + } +} +export const completeUploadResult = ( + extFile: ExtFile, + serverResponse: ServerResponse, + result: UPLOADSTATUS +): UploadResponse => { + return { + id: extFile.id, + uploadedFile: { + ...extFile, + uploadMessage: serverResponse.message, + uploadStatus: result + }, + serverResponse: serverResponse + } +} + +/** + * Initializes the xhr attribute for performing uploads + * @param extFileList the list of extended files + * @returns the array of extFiles with the xhr attribute initialized + */ +export const toUploadableExtFileList = ( + extFileList: ExtFile[] | ExtFileInstance[] + ): ExtFile[] => { + if (!extFileList) return []; + return extFileList.map(extFile => { + return { ...extFile, xhr: new XMLHttpRequest() } + }); +} + +/** + * Updates the uploadStatus of the given extFile + * from "preparing" to "uploading" + * @param extFile the extended file + * @returns the extended file with uploadStatus updated to "uploading" + */ +export const instantPreparingToUploadOne = ( + extFile: ExtFileInstance | ExtFile +): ExtFileInstance | ExtFile => { + if (extFile.uploadStatus === "preparing") { + //for ExtFile instance + extFile.uploadStatus = "uploading"; + //for ExtFile type + return { + ...extFile, + uploadStatus: "uploading", + }; + } + return extFile; +}; + +/** + * + * @param extFile the extended file + * @returns + */ +export const preparingToUploadOne = ( + extFile: ExtFileInstance | ExtFile +): Promise<ExtFileInstance | ExtFile> => { + return new Promise((resolve, reject) => { + setTimeout(() => { + if (extFile.uploadStatus === "preparing") { + //for ExtFile instance + extFile.uploadStatus = "uploading"; + //for ExtFile type + resolve({ + ...extFile, + uploadStatus: "uploading", + }); + } else + resolve(extFile); + }, 1500); + }); +}; +/** + * Sleeps for 1200 miliseconds for showing a better transition + * on uploading + * @returns true is everything is ok + */ +export const sleepTransition = ( +): Promise<boolean> => { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(true); + }, 1200); + }); +} + diff --git a/src/pages/api/AvatarApi.jsx b/src/pages/api/AvatarApi.jsx new file mode 100644 index 0000000000000000000000000000000000000000..ab2e3674029b192068f132917cb8a6e14a2b9b97 --- /dev/null +++ b/src/pages/api/AvatarApi.jsx @@ -0,0 +1,10 @@ +import * as React from "react"; + +const AvatarApi = props =>{ + return( + <div> + AvatarApi + </div> + ) +} +export default AvatarApi; \ No newline at end of file diff --git a/src/pages/api/FileMosaicApi.jsx b/src/pages/api/FileMosaicApi.jsx index f30a2d029c9c920323dc97b5a1e0594f3b76189f..e625b43c4dd0a448c201f19c95e7f5a348d6613c 100644 --- a/src/pages/api/FileMosaicApi.jsx +++ b/src/pages/api/FileMosaicApi.jsx @@ -15,12 +15,12 @@ const rightMenuItems = [ { id: 0, label: "Demos", - referTo: "/api/file-mosaic/#filemosaic-demo", + referTo: "/api/file-mosaic#filemosaic-demo", }, { id: 1, label: "Props", - referTo: "/api/file-mosaic/#filemosaic-props", + referTo: "/api/file-mosaic#filemosaic-props", }, ]; const FileMosaicApi = (props) => { diff --git a/src/pages/api/InputButtonApi.jsx b/src/pages/api/InputButtonApi.jsx new file mode 100644 index 0000000000000000000000000000000000000000..2009b718a214f8e73f3156d405bd1cabf22bbac2 --- /dev/null +++ b/src/pages/api/InputButtonApi.jsx @@ -0,0 +1,10 @@ +import * as React from "react"; + +const InputButtonApi = props =>{ + return( + <div> + InputButtonApi + </div> + ) +} +export default InputButtonApi; \ No newline at end of file diff --git a/src/pages/demo/AvatarDemoPage.tsx b/src/pages/demo/AvatarDemoPage.tsx new file mode 100644 index 0000000000000000000000000000000000000000..10e21596180303b3280c6e65dcc5f221c414b5ef --- /dev/null +++ b/src/pages/demo/AvatarDemoPage.tsx @@ -0,0 +1,146 @@ +import { Alert, AlertTitle, Paper } from "@mui/material"; +import * as React from "react"; +import CodeHighlight from "../../components/codeHighlight/CodeHighlight"; +import BasicDemoAvatar from "../../components/demo-components/avatar-demo/BasicDemoAvatar"; +import DescParagraph from "../../components/demo-components/desc-paragraph/DescParagraph"; +import SubTitle from "../../components/demo-components/sub-title/SubTitle"; +import MainContentContainer from "../../components/layout-pages/MainContentContainer"; +import RightMenuContainer from "../../components/layout-pages/RightMenuContainer"; +import MainTitle from "../../components/main-title/MainTitle"; +import MainParagraph from "../../components/paragraph-main/MainParagraph"; +import RightMenu from "../../components/RightMenu/RightMenu"; +import TypeHighlight from "../../components/typeHighlight/TypeHighlight"; + +const rightMenuItems = [ + { + id: 0, + label: "Basic dropzone", + referTo: "/components/dropzone#basic-dropzone", + }, + { + id: 1, + label: "Validation", + referTo: "/components/dropzone#validation", + }, + { + id: 1, + label: "Custom validation", + referTo: "/components/dropzone#custom-validation", + }, + { + id: 2, + label: "Dropzone events", + referTo: "/components/dropzone#dropzone-events", + }, + { + id: 3, + label: "Uploading", + referTo: "/components/dropzone#uploading", + }, + { + id: 4, + label: "Styling", + referTo: "/components/dropzone#styling", + }, + { + id: 5, + label: "Localization", + referTo: "/components/dropzone#localization", + }, + { + id: 6, + label: "Dark mode", + referTo: "/components/dropzone#dark-mode", + }, +]; + +interface AvatarDemoPageProps {} +const AvatarDemoPage: React.FC<AvatarDemoPageProps> = ( + props: AvatarDemoPageProps +) => { + return ( + <React.Fragment> + <MainContentContainer> + <MainTitle>Avatar</MainTitle> + + <MainParagraph> + The "avatar" component is a special file{" "} + <CodeHighlight>input</CodeHighlight> designed for setting an image by + either dragging and dropping files there or by picking files from a + file dialog. + </MainParagraph> + + <DescParagraph> + You can consider that this widget is a kind of combination between + dropzone and file mosaic components. + <ol> + <li>The image</li> + <li> + The file(s) must be validated or not. If validation is required, + it can be done by taking into account a predefined set of allowed{" "} + <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#accept"> + Common MIME Types + </a> + ; specifiying the max file size (in bytes) and/or the max amount + of files. + </li> + <li>The file(s) must be uploaded somewhere in the internet.</li> + </ol> + </DescParagraph> + <DescParagraph> + It's meant to be an improved version of the "react-dropzone" and + "dropzone" packages. + </DescParagraph> + + <section id="basic-avatar"> + <SubTitle content="Basic Avatar" /> + <DescParagraph> + In this demo we set avatar with the minimun props that allows you to + get done fast. These props are{" "} + <CodeHighlight>onChange</CodeHighlight> and{" "} + <CodeHighlight>value</CodeHighlight>. + </DescParagraph> + <Paper + variant="outlined" + style={{ + padding: "25px", + display: "flex", + width: "100%", + alignItems: "center", + }} + > + <BasicDemoAvatar /> + </Paper> + {"<BasicDemoAvatarCode/>>"} + {/* <BasicDropzoneCodeJS /> */} + <Alert severity="info"> + <AlertTitle> FileMosaic </AlertTitle> + For completeness, these examples include{" "} + <CodeHighlight>{`<FileMosaic/>`} </CodeHighlight> + component for showing the files selected by the user with minimun + props too. For further information of this component check out the{" "} + <a href="/components/filemosaic">FileMosaic</a> page. + </Alert> + <br /> + <Alert severity="info"> + <AlertTitle> ExtFile </AlertTitle> + {/* This is an info alert — <strong>check it out!</strong> + */} + <strong>ExtFile type </strong> + is explicity used in the + <strong> Typescript</strong> example and is implicity used in the{" "} + <strong>Javascript</strong> example for handling the metadata that + makes possible the information exchange between components. For + further information about this data type check out the{" "} + <a href="/types#ext-file">ExtFile-API. </a> + </Alert> + </section> + </MainContentContainer> + + <RightMenuContainer> + <RightMenu width="240px" items={rightMenuItems} /> + </RightMenuContainer> + </React.Fragment> + ); +}; +export default AvatarDemoPage; diff --git a/src/pages/demo/DropzoneDemoPage.jsx b/src/pages/demo/DropzoneDemoPage.jsx index 8b418613267023bc3059ce9e5618cf9faf8ad3e1..5fb092256a64ccd38cd88182774ada4d774134d3 100644 --- a/src/pages/demo/DropzoneDemoPage.jsx +++ b/src/pages/demo/DropzoneDemoPage.jsx @@ -17,44 +17,43 @@ const rightMenuItems = [ { id: 0, label: "Basic dropzone", - referTo: "/components/dropzone/#basic-dropzone", + referTo: "/components/dropzone#basic-dropzone", }, { id: 1, label: "Validation", - referTo: "/components/dropzone/#validation", + referTo: "/components/dropzone#validation", }, { id: 1, label: "Custom validation", - referTo: "/components/dropzone/#custom-validation", + referTo: "/components/dropzone#custom-validation", }, { id: 2, label: "Dropzone events", - referTo: "/components/dropzone/#dropzone-events", + referTo: "/components/dropzone#dropzone-events", }, { id: 3, label: "Uploading", - referTo: "/components/dropzone/#uploading", + referTo: "/components/dropzone#uploading", }, { id: 4, label: "Styling", - referTo: "/components/dropzone/#styling", + referTo: "/components/dropzone#styling", }, { id: 5, label: "Localization", - referTo: "/components/dropzone/#localization", + referTo: "/components/dropzone#localization", }, { id: 6, label: "Dark mode", - referTo: "/components/dropzone/#dark-mode", + referTo: "/components/dropzone#dark-mode", }, - ]; const DropzoneDemoPage = (props) => { return ( @@ -80,18 +79,15 @@ const DropzoneDemoPage = (props) => { and dropped into the widget </li> <li> - The file(s) must be validated or not taking into account a - predefined set of allowed{" "} + The file(s) must be validated or not. If validation is required, + it can be done by taking into account a predefined set of allowed{" "} <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#accept"> Common MIME Types </a> - ; specifiying the max file size (in bytes) or max amout of files. + ; specifiying the max file size (in bytes) and/or the max amount + of files. </li> <li>The file(s) must be uploaded somewhere in the internet.</li> - <li> - The file(s) must be shown in the screen with a preview according - to the file type. - </li> </ol> </DescParagraph> <DescParagraph> @@ -104,8 +100,8 @@ const DropzoneDemoPage = (props) => { <DescParagraph> In this demo we set dropzone with the minimun props that allows you to get done fast. These props are{" "} - <code className="code">onChange</code> and{" "} - <code className="code">value</code> props. + <CodeHighlight>onChange</CodeHighlight> and{" "} + <CodeHighlight>value</CodeHighlight>. </DescParagraph> <Paper variant="outlined" style={{ padding: "25px" }}> <BasicDemoDropzone /> @@ -114,7 +110,7 @@ const DropzoneDemoPage = (props) => { <Alert severity="info"> <AlertTitle> FileMosaic </AlertTitle> For completeness, these examples include{" "} - <strong>{`<FileMosaic/>`} </strong> + <CodeHighlight>{`<FileMosaic/>`} </CodeHighlight> component for showing the files selected by the user with minimun props too. For further information of this component check out the{" "} <a href="/components/filemosaic">FileMosaic</a> page. @@ -134,43 +130,52 @@ const DropzoneDemoPage = (props) => { </Alert> </section> - {/* <section id="validation"> - <SubTitle content="Validation" /> - <DescParagraph> - You can either "tell" Dropzone component to validate user files by - providing one or more of these criteria: - <ol> - <li>Accept specific file types.</li> - <li>Accept an specific number of files.</li> - <li>Accept an specific size (in bytes) of files.</li> - </ol> - </DescParagraph> - - <Paper variant="outlined" style={{ padding: "25px" }}> - <BasicDemoDropzone /> - </Paper> + <section id="validation"> + <SubTitle content="Validation" /> + <DescParagraph> + You can either "tell" Dropzone component to validate user files by + providing one or more of these criteria: + <ol> + <li>Accept specific file types.</li> + <li>Accept an specific number of files.</li> + <li>Accept an specific size (in bytes) of files.</li> + </ol> + </DescParagraph> - <p></p> - <BasicDropzoneCodeJS /> - </section> + <Paper variant="outlined" style={{ padding: "25px" }}> + <BasicDemoDropzone /> + </Paper> - <section id="custom-validation"> - <SubTitle content="Custom validation" /> - <DescParagraph> - You can also "override the Dropzone validation by performimg a custom - validation using a custom function that must fit the following - signature: - <div>... type</div> - </DescParagraph> + <p></p> + <BasicDropzoneCodeJS /> + </section> - <Paper variant="outlined" style={{ padding: "25px" }}> - <BasicDemoDropzone /> - </Paper> + <section id="custom-validation"> + <SubTitle content="Custom validation" /> + <DescParagraph> + You can also "override the Dropzone validation by giving a custom + validation function that must fit the following signature:{" "} + <CodeHighlight> + {"validator?: (f: "} + <a href="https://developer.mozilla.org/en-US/docs/Web/API/File"> + File + </a> + {") => "} + <a href="/types#custom-validate-file-response"> + CustomValidateFileResponse + </a> + </CodeHighlight> + . + </DescParagraph> - <p></p> - <BasicDropzoneCodeJS /> - </section> + <Paper variant="outlined" style={{ padding: "25px" }}> + <BasicDemoDropzone /> + </Paper> + <p></p> + <BasicDropzoneCodeJS /> + </section> + {/* <section id="dropzone-events"> <SubTitle content="Dropzone events" /> <DescParagraph> diff --git a/src/pages/demo/FileCardDemoPage.jsx b/src/pages/demo/FileCardDemoPage.jsx index e8baae8e7e697ade432493a6ffada8855cf951ff..ffa5c15ef7ab2573995b1180a6f5b8a55d2c0d63 100644 --- a/src/pages/demo/FileCardDemoPage.jsx +++ b/src/pages/demo/FileCardDemoPage.jsx @@ -101,46 +101,46 @@ const rightMenuItems = [ { id: 0, label: "Basic file mosaic", - referTo: "/components/file-mosaic/#basic-filemosaic", + referTo: "/components/file-mosaic#basic-filemosaic", }, { id: 1, label: "Image Preview", - referTo: "/components/file-mosaic/#file-mosaic-image-preview", + referTo: "/components/file-mosaic#file-mosaic-image-preview", }, { id: 2, label: "Validation", - referTo: "/components/file-mosaic/#file-mosaic-validation", + referTo: "/components/file-mosaic#file-mosaic-validation", }, { id: 3, label: "Uploading", - referTo: "/components/file-mosaic/#file-mosaic-uploading", + referTo: "/components/file-mosaic#file-mosaic-uploading", }, { id: 4, label: "Localization", - referTo: "/components/file-mosaic/#file-mosaic-localization", + referTo: "/components/file-mosaic#file-mosaic-localization", }, { id: 5, label: "Previews", - referTo: "/components/file-mosaic/#file-mosaic-previews", + referTo: "/components/file-mosaic#file-mosaic-previews", }, { id: 6, label: "Actions", - referTo: "/components/file-mosaic/#actions", + referTo: "/components/file-mosaic#actions", }, { id: 7, label: "Default previews", - referTo: "/components/file-mosaic/#default-previews", + referTo: "/components/file-mosaic#default-previews", }, { id: 8, label: "Dark mode", - referTo: "/components/file-mosaic/#dark-mode", + referTo: "/components/file-mosaic#dark-mode", }, ]; diff --git a/src/pages/demo/FileMosaicDemoPage.jsx b/src/pages/demo/FileMosaicDemoPage.jsx index 175628861e63c46b42ad99f3acbc6a0e05fe7280..cff97b584dd152da03654955e246d154ed5fbf3c 100644 --- a/src/pages/demo/FileMosaicDemoPage.jsx +++ b/src/pages/demo/FileMosaicDemoPage.jsx @@ -24,8 +24,8 @@ const FileMosaicDemoPage = (props) => { allow the user to interact with them. </MainParagraph> <DescParagraph> - This widget allow users to see information of Files and / or trigger - actions. + This widget allow users to see information of{" "} + <TypeHighlight> Files</TypeHighlight> and / or trigger actions. </DescParagraph> <Alert severity="info"> While included here as a standalone component, the most common use @@ -100,46 +100,46 @@ const rightMenuItems = [ { id: 0, label: "Basic file mosaic", - referTo: "/components/file-mosaic/#basic-filemosaic", + referTo: "/components/file-mosaic#basic-filemosaic", }, { id: 1, label: "Image Preview", - referTo: "/components/file-mosaic/#file-mosaic-image-preview", + referTo: "/components/file-mosaic#file-mosaic-image-preview", }, { id: 2, label: "Validation", - referTo: "/components/file-mosaic/#file-mosaic-validation", + referTo: "/components/file-mosaic#file-mosaic-validation", }, { id: 3, label: "Uploading", - referTo: "/components/file-mosaic/#file-mosaic-uploading", + referTo: "/components/file-mosaic#file-mosaic-uploading", }, { id: 4, label: "Localization", - referTo: "/components/file-mosaic/#file-mosaic-localization", + referTo: "/components/file-mosaic#file-mosaic-localization", }, { id: 5, label: "Previews", - referTo: "/components/file-mosaic/#file-mosaic-previews", + referTo: "/components/file-mosaic#file-mosaic-previews", }, { id: 6, label: "Actions", - referTo: "/components/file-mosaic/#actions", + referTo: "/components/file-mosaic#actions", }, { id: 7, label: "Default previews", - referTo: "/components/file-mosaic/#default-previews", + referTo: "/components/file-mosaic#default-previews", }, { id: 8, label: "Dark mode", - referTo: "/components/file-mosaic/#dark-mode", + referTo: "/components/file-mosaic#dark-mode", }, ]; diff --git a/src/pages/demo/InputButtonDemoPage.tsx b/src/pages/demo/InputButtonDemoPage.tsx new file mode 100644 index 0000000000000000000000000000000000000000..bf808d2d07f806874d0fb1172ae7e457e3cdbb81 --- /dev/null +++ b/src/pages/demo/InputButtonDemoPage.tsx @@ -0,0 +1,10 @@ +import * as React from "react"; +interface InputButtonDemoPageProps{} +const InputButtonDemoPage:React.FC<InputButtonDemoPageProps> = (props:InputButtonDemoPageProps) =>{ + return( + <div> + InputButtonDemoPage + </div> + ) +} +export default InputButtonDemoPage; \ No newline at end of file diff --git a/src/pages/getting-started/GettingStartedPage.jsx b/src/pages/getting-started/GettingStartedPage.jsx index 19fa607e21e92d58d28305361884a7d3301089f7..65168938558a1f9e149fdb84016d5e0a70df5199 100644 --- a/src/pages/getting-started/GettingStartedPage.jsx +++ b/src/pages/getting-started/GettingStartedPage.jsx @@ -21,7 +21,7 @@ import RightMenuContainer from "../../components/layout-pages/RightMenuContainer const GettingStartedPage = ({ darkModeOn }) => { return ( <MainLayoutPage selectedIndex={0}> - <MainContentContainer > + <MainContentContainer> <Stack sx={{ width: "100%", alignItems: "center" }}> <img className="fui-logo-img-getting-started" @@ -75,18 +75,17 @@ const rightMenuItems = [ { id: 0, label: "Overview", - referTo: "/getting-started/#overview", + referTo: "/getting-started#overview", }, { id: 1, label: "Installation", - referTo: "/getting-started/#installation", + referTo: "/getting-started#installation", }, { id: 2, label: "Peer dependency", - referTo: "/getting-started/#peer-dependency", + referTo: "/getting-started#peer-dependency", }, - { id: 3, label: "Default font", referTo: "/getting-started/#default-font" }, - + { id: 3, label: "Default font", referTo: "/getting-started#default-font" }, ]; diff --git a/src/pages/usage/UsagePage.jsx b/src/pages/usage/UsagePage.jsx index 611c2a4e583f180829efda51cd28e4dc6b56782b..ba05fd94df48edba13293bcb787659bc9a6dbf8b 100644 --- a/src/pages/usage/UsagePage.jsx +++ b/src/pages/usage/UsagePage.jsx @@ -19,11 +19,11 @@ import RightMenuContainer from "../../components/layout-pages/RightMenuContainer import MainContentContainer from "../../components/layout-pages/MainContentContainer"; import MainTitle from "../../components/main-title/MainTitle"; const rightMenuItems = [ - { id: 0, label: "Quick start", referTo: "/usage/#quick-start" }, + { id: 0, label: "Quick start", referTo: "/usage#quick-start" }, { id: 1, label: "Advanced examples", - referTo: "/usage/#advanced-example", + referTo: "/usage#advanced-example", }, ]; const UsagePage = (props) => { @@ -48,7 +48,7 @@ const UsagePage = (props) => { <CodeHighlight>onChange</CodeHighlight> and{" "} <CodeHighlight>value</CodeHighlight> props. This example is the same as the one you will find in the{" "} - <a href="/components/dropzone/#basic-dropzone">Basic dropzone</a>{" "} + <a href="/components/dropzone#basic-dropzone">Basic dropzone</a>{" "} section. </DescParagraph>{" "} <BasicDropzoneCodeJS splittedOnly /> @@ -57,7 +57,7 @@ const UsagePage = (props) => { </Paper>{" "} */} <DescParagraph> You can play around with this code in the interactive Code Sandbox - demo below. Try changing the <CodeHighlight>label</CodeHighlight> on + demo below. Try adding the <CodeHighlight>accept</CodeHighlight> prop to the Dropzone to see the changes: </DescParagraph> {/* <iframe diff --git a/src/routes/MainRouter.jsx b/src/routes/MainRouter.jsx index bc65ae2dfdb5f4f0201d7b11f1d52068325da56f..eaf9743be190805a534e597fa50cebcd328234e8 100644 --- a/src/routes/MainRouter.jsx +++ b/src/routes/MainRouter.jsx @@ -16,6 +16,10 @@ import { createBrowserRouter, Outlet, RouterProvider } from "react-router-dom"; import MainLayoutPage from "../components/layout-pages/MainLayoutPage"; import FileReaderPage from "../pages/utilities/FileReaderPage"; import FileUploaderPage from "../pages/utilities/FileUploaderPage"; +import InputButtonDemoPage from "../pages/demo/InputButtonDemoPage"; +import AvatarDemoPage from "../pages/demo/AvatarDemoPage"; +import InputButtonApi from "../pages/api/InputButtonApi"; +import AvatarApi from "../pages/api/AvatarApi"; const router = createBrowserRouter([ { @@ -43,10 +47,18 @@ const router = createBrowserRouter([ </MainLayoutPage> ), children: [ + { + path: "/components/avatar", + element: <AvatarDemoPage />, + }, { path: "/components/dropzone", element: <DropzoneDemoPage />, }, + { + path: "/components/inputbutton", + element: <InputButtonDemoPage />, + }, { path: "/components/filemosaic", element: <FileMosaicDemoPage />, @@ -65,6 +77,14 @@ const router = createBrowserRouter([ </MainLayoutPage> ), children: [ + { + path: "/api/avatar", + element: <AvatarApi />, + }, + { + path: "/api/inputbutton", + element: <InputButtonApi />, + }, { path: "/api/dropzone", element: <DropzoneApi />, diff --git a/src/static/new-icons/Microsoft.VisualStudio.Services.Icons.Default.png b/src/static/new-icons/Microsoft.VisualStudio.Services.Icons.Default.png new file mode 100644 index 0000000000000000000000000000000000000000..386be5b3030db509f506f11abf97af66ab29c4ec Binary files /dev/null and b/src/static/new-icons/Microsoft.VisualStudio.Services.Icons.Default.png differ diff --git a/src/static/new-icons/gradle.jpg b/src/static/new-icons/gradle.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5a87d77a1058c57306cd434599ae6bd487489af7 Binary files /dev/null and b/src/static/new-icons/gradle.jpg differ diff --git a/src/static/new-icons/images.png b/src/static/new-icons/images.png new file mode 100644 index 0000000000000000000000000000000000000000..ca61510a9d20959d3740958f27e0702b91fe1986 Binary files /dev/null and b/src/static/new-icons/images.png differ diff --git a/src/static/new-icons/markdown-fill-1.png b/src/static/new-icons/markdown-fill-1.png new file mode 100644 index 0000000000000000000000000000000000000000..37a31624e2eba4cfda902bea852d896680c881c4 Binary files /dev/null and b/src/static/new-icons/markdown-fill-1.png differ diff --git a/src/static/new-icons/maven_logo.png b/src/static/new-icons/maven_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..990203c90a2fcdcffbdfc8b4de975ef237e0107c Binary files /dev/null and b/src/static/new-icons/maven_logo.png differ diff --git a/Captura de pantalla (3946).png b/src/static/other/Captura de pantalla (3946).png similarity index 100% rename from Captura de pantalla (3946).png rename to src/static/other/Captura de pantalla (3946).png diff --git a/ref mt.png b/src/static/other/ref mt.png similarity index 100% rename from ref mt.png rename to src/static/other/ref mt.png diff --git a/src/templates/NavBarTemplate.jsx b/src/templates/NavBarTemplate.jsx index 273e8bd0fb4d47d8a18a1b7fe17708aab2a99aaa..6886ff93d4d37190da6c1d5c86ea39d2419848ad 100644 --- a/src/templates/NavBarTemplate.jsx +++ b/src/templates/NavBarTemplate.jsx @@ -75,9 +75,9 @@ function NavBarTemplate(props) { <img src={darkModeOn ? logo_text_blue_dark : logo_text_blue} alt="files-ui-main-logo-text" - height={20} + height={16} /> - {/* <Typography variant="h6" noWrap component="div" color="primary"> + {/* <Typography variant="h6" noWrap component="div" color="primary"> Files ui </Typography> */} </Stack> diff --git a/src/tester/AvatarTester.tsx b/src/tester/AvatarTester.tsx new file mode 100644 index 0000000000000000000000000000000000000000..9e691c9b71ad2823b8f1106a4adfa4bbf6eb1c7c --- /dev/null +++ b/src/tester/AvatarTester.tsx @@ -0,0 +1,80 @@ +import * as React from "react"; +import { Avatar } from "../files-ui"; +import { + ServerResponse, + //UploadPromiseResponse, + //uploadPromiseXHR, +} from "../files-ui/core"; + +import { uploadFile } from "../files-ui/core"; + +export const resultURL: string = + "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQ1YdE-2sQT4na6RwujeATyMBcCXqg0Gf76TYTplRkMkq0wIi_SewCDq6VeUGxPwpK_Qd8&usqp=CAU"; +export const initURL: string = + "https://sm.ign.com/ign_latam/screenshot/default/goku-ssj-blue-3_6qjv.jpg"; + +const rowStyle: React.CSSProperties = { + display: "flex", + flexDirection: "row", + padding: "20px", + border: "1px dotted orange", + borderRadius: "8px", + boxSizing: "border-box", + margin: "25px 0", + backgroundColor: "white", + gap: "15px", +}; + + +const REMOTE = "https://files-ui-express-static-file-storage.vercel.app/39d33dff2d41b522c1ea276c4b82507f96b9699493d2e7b3f5c864ba743d9503"; +const LOCAL = "http://localhost/39d33dff2d41b522c1ea276c4b82507f96b9699493d2e7b3f5c864ba743d9503"; + + +interface AvatarTesterProps {} +const AvatarTester: React.FC<AvatarTesterProps> = ( + props: AvatarTesterProps +) => { + const [avatarSrc, setAvatarSrc] = React.useState<string | undefined>( + undefined + ); + + /* const handleChange = async (file: File) => { + const endpoint: string = "http://localhost:2800/upload-avatar"; + const response: UploadPromiseResponse = await uploadPromiseXHR( + { id: 0, file: file, xhr: new XMLHttpRequest() }, + endpoint, + "POST", + { + Authorization: "bearer bJUKYIBVUKIBHUKYIBHVKULIUBHKLÑBJ", + "z-header": "HAAAAAAA", + } + ); + // const res: boolean = uploadFile(file, endpoint); + const serverResponse: ServerResponse = response.uploadResponse + .serverResponse as ServerResponse; + const { url } = serverResponse.payload; + setAvatarSrc(url); + console.log(serverResponse.payload); + }; */ + + const handleChange2 = async (file: File) => { + const endpoint: string = REMOTE + "/file/28048465460"; + const res: ServerResponse = await uploadFile(file, endpoint); + const { url } = res.payload; + setAvatarSrc(url); + }; + + return ( + <React.Fragment> + <div style={rowStyle}> + <Avatar + src={avatarSrc} + variant="circle" + style={{ width: "300px", height: "300px" }} + onChange={handleChange2} + /> + </div> + </React.Fragment> + ); +}; +export default AvatarTester; diff --git a/use-cases.md b/use-cases.md new file mode 100644 index 0000000000000000000000000000000000000000..8cc66f90d2dd1b2da13235ef7678d1b32841dab0 --- /dev/null +++ b/use-cases.md @@ -0,0 +1,2 @@ +# Files -ui Use Cases +- set the thumbnail, after loads the hd image show loader \ No newline at end of file