app/javascript/components/Attachments/Attachment.tsx
import { MouseEvent } from "react";import copyToClipboard from "../../lib/copyToClipboard";import AttachmentEditor from "./AttachmentEditor";import useModalStore from "../../stores/useModalStore";import useToastStore from "../../stores/useToastStore";import * as Attachments from "../../types/Attachments";import * as Drag from "../../types/Drag";import { Locale } from "../../types"; import { useDraggable } from "../drag"; type Props = { attributeName: string; placeholder: boolean; draggable: Drag.Draggable<Attachments.Record>; locale: string; locales: { [index: string]: Locale }; deleteRecord: () => void; showEmbed: boolean; position: number; onUpdate: (attachment: Partial<Attachments.Resource>) => void; startDrag: ( evt: MouseEvent, draggable: Drag.Draggable<Attachments.Record> ) => void;}; Function `Attachment` has 98 lines of code (exceeds 25 allowed). Consider refactoring.
Function `Attachment` has a Cognitive Complexity of 18 (exceeds 5 allowed). Consider refactoring.export default function Attachment(props: Props) { const { attributeName, draggable, locales, locale } = props; const { record } = draggable; const { attachment, uploading } = record; const openModal = useModalStore((state) => state.open); const notice = useToastStore((state) => state.notice); const listeners = useDraggable<Attachments.Record>( draggable, props.startDrag ); Similar blocks of code found in 3 locations. Consider refactoring. const copyEmbed = (evt: MouseEvent) => { evt.preventDefault(); copyToClipboard(`[attachment:${attachment.id}]`); notice("Embed code copied to clipboard"); }; Similar blocks of code found in 2 locations. Consider refactoring. const deleteRecord = (evt: MouseEvent) => { evt.preventDefault(); if (props.deleteRecord) { props.deleteRecord(); } }; Similar blocks of code found in 2 locations. Consider refactoring. const description = () => { if (attachment.description && attachment.description[locale]) { return attachment.description[locale]; } return null; }; Similar blocks of code found in 2 locations. Consider refactoring. const name = () => { if (attachment.name && attachment.name[locale]) { return attachment.name[locale]; } return null; }; const editAttachment = (evt: MouseEvent) => { evt.preventDefault(); openModal( <AttachmentEditor attachment={attachment} locale={locale} locales={locales} onUpdate={props.onUpdate} /> ); }; const classes = ["attachment"]; if (props.placeholder) { classes.push("placeholder"); } if (record.uploading) { classes.push("uploading"); } const icon = uploading ? "cloud-arrow-up" : "paperclip"; let localeDir = "ltr"; if (locale in locales && locales[locale].dir) { localeDir = locales[locale].dir; } return ( <div className={classes.join(" ")} {...listeners}> <input name={`${attributeName}[id]`} type="hidden" value={record.id || ""} />Similar blocks of code found in 2 locations. Consider refactoring. <input name={`${attributeName}[attachment_id]`} type="hidden" value={(attachment && attachment.id) || ""} /> <input name={`${attributeName}[position]`} type="hidden" value={props.position} /> {!uploading && ( <div className="actions"> <button onClick={editAttachment}>Edit</button> {props.showEmbed && <button onClick={copyEmbed}>Embed</button>} {props.deleteRecord && <button onClick={deleteRecord}>Remove</button>} </div> )} {attachment && ( <div className="attachment-info"> <h3> <i className={`fa-solid fa-${icon} icon`} /> {name() || <em>Untitled</em>} <br /> </h3> {!uploading && ( <a href={attachment.url} rel="noreferrer" target="_blank"> {attachment.filename} </a> )} {!uploading && description() && ( <p dir={localeDir}>{description()}</p> )} </div> )} </div> );}