app/javascript/components/ImageUploader.tsx
import { DragEvent, MouseEvent, useState } from "react"; import useToastStore from "../stores/useToastStore";import { post } from "../lib/request";import * as Images from "../types/Images";import { Locale } from "../types"; import EditableImage from "./EditableImage";import FileUploadButton from "./FileUploadButton"; type Props = { locale: string; locales: { [index: string]: Locale }; image: Images.Resource; src: string; width: number; caption: boolean; attr: string; alternative?: string; onChange?: (state: State) => void;}; type State = { image?: Images.Resource; src?: string;}; Function `getFiles` has a Cognitive Complexity of 9 (exceeds 5 allowed). Consider refactoring.
Identical blocks of code found in 2 locations. Consider refactoring.function getFiles(dt: DataTransfer): File[] { const files: File[] = []; if (dt.items) { for (let i = 0; i < dt.items.length; i++) { if (dt.items[i].kind == "file") { files.push(dt.items[i].getAsFile()); } } } else { for (let i = 0; i < dt.files.length; i++) { files.push(dt.files[i]); } } return files;} Function `ImageUploader` has 132 lines of code (exceeds 25 allowed). Consider refactoring.
Function `ImageUploader` has a Cognitive Complexity of 27 (exceeds 5 allowed). Consider refactoring.export default function ImageUploader(props: Props) { const [uploading, setUploading] = useState(false); const [dragover, setDragover] = useState(false); const [state, setState] = useState<State>({ image: props.image, src: props.src }); const { image, src } = props.onChange ? props : state; const error = useToastStore((state) => state.error); const update = (image: Images.Resource | null, src?: string) => { const handler = props.onChange || setState; handler({ image: image, src: src || null }); }; const handleDragOver = (evt: DragEvent) => { evt.preventDefault(); setDragover(true); }; const handleDragLeave = () => { setDragover(false); }; const handleDragEnd = (evt: DragEvent) => { if ("dataTransfer" in evt) { if ("items" in evt.dataTransfer && "remove" in evt.dataTransfer.items) { for (let i = 0; i < evt.dataTransfer.items.length; i++) { evt.dataTransfer.items.remove(i); } } else if ("clearData" in evt.dataTransfer) { evt.dataTransfer.clearData(); } } setDragover(false); }; const handleDrop = (evt: DragEvent) => { let files: File[] = []; if ("dataTransfer" in evt) { files = getFiles(evt.dataTransfer); } evt.preventDefault(); if (files.length > 0) { uploadImage(files[0]); } }; const handleRemove = (evt: MouseEvent) => { evt.preventDefault(); update(null); }; const receiveFiles = (files: File[]) => { if (files.length > 0) { uploadImage(files[0]); } }; Function `uploadImage` has 32 lines of code (exceeds 25 allowed). Consider refactoring. const uploadImage = (file: File) => { const validTypes = [ "image/gif", "image/jpeg", "image/pjpeg", "image/png", "image/tiff" ]; if (validTypes.indexOf(file.type) == -1) { alert( "Invalid file type, only images in JPEG, PNG or GIF " + "formats are supported" ); return; } const locale = props.locale; const locales = props.locales ? Object.keys(props.locales) : [locale]; const data = new FormData(); update(null); setDragover(false); setUploading(true); data.append("image[file]", file); locales.forEach((l) => { data.append(`image[alternative][${l}]`, props.alternative || ""); }); void post("/admin/images.json", data).then((response: Images.Response) => { setUploading(false); if ("status" in response && response.status === "error") { error(`Error uploading image: ${response.error}`); } else if ("thumbnail_url" in response) { update(response, response.thumbnail_url); } }); }; const classes = ["image-uploader"]; if (uploading) { classes.push("uploading"); } else if (dragover) { classes.push("dragover"); } return ( <div className={classes.join(" ")} onDragOver={handleDragOver} onDragLeave={handleDragLeave} onDragEnd={handleDragEnd} onDrop={handleDrop}> <input type="hidden" name={props.attr} value={image ? image.id : ""} /> {image && ( <div className="image"> <EditableImage image={image} src={src} width={props.width} caption={props.caption} locale={props.locale} locales={props.locales} /> </div> )} <div className="ui-wrapper"> {uploading && <div className="ui">Uploading image...</div>} {!uploading && ( <div className="ui"> <FileUploadButton type="image" multiline={true} callback={receiveFiles} /> {image && ( <a className="delete remove-image" href="#" onClick={handleRemove}> Remove image </a> )} </div> )} </div> </div> );}