From f69a174850398abbab7280a09918449a24ca4f44 Mon Sep 17 00:00:00 2001 From: Lucas Henrique Ramos <82041293+luckramos@users.noreply.github.com> Date: Mon, 9 Sep 2024 12:00:36 -0300 Subject: [PATCH] feat(ui): Add a resize button to the image content card (#142) * feat(ui): Add a resize button to the image content card Add a resize button that opens a modal and let the user change both the width and height of the image * fix(ui): use the previous toast id instead of dismissing it when resizing images --- ui/src/actions/handleResizeImage.ts | 36 +++++++++ ui/src/components/content-card.tsx | 10 ++- ui/src/components/resize-modal.tsx | 118 ++++++++++++++++++++++++++++ ui/src/types/imageDimensions.ts | 4 + 4 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 ui/src/actions/handleResizeImage.ts create mode 100644 ui/src/components/resize-modal.tsx create mode 100644 ui/src/types/imageDimensions.ts diff --git a/ui/src/actions/handleResizeImage.ts b/ui/src/actions/handleResizeImage.ts new file mode 100644 index 0000000..a6134e6 --- /dev/null +++ b/ui/src/actions/handleResizeImage.ts @@ -0,0 +1,36 @@ +import { ImageDimensions } from "@/types/imageDimensions"; +import axios from "axios"; +import { FormEvent } from "react"; +import toast from "react-hot-toast"; + +const handleResizeImage = (e: FormEvent, newDimensions: ImageDimensions, filename: string) => { + e.preventDefault(); + + const {width, height} = newDimensions; + + if(!width || !height) { + toast.error("Width and height are required!") + return; + } + + const data = { + filename, + width: Math.abs(Math.floor(width)), + height: Math.abs(Math.floor(height)) + }; + + const toastId = toast.loading("Renaming file..."); + axios.put(`/api/cdn/resize/image`, JSON.stringify(data)).then((res) => { + if (res.status === 200) { + toast.success("File resized!", { id: toastId, duration: 1500 }); + + setTimeout(() => { + location.reload(); + }, 1500) + } + }).catch((err) => { + toast.error("Error: " + err.response.data, { id: toastId, duration: 4000 }); + }) +} + +export default handleResizeImage \ No newline at end of file diff --git a/ui/src/components/content-card.tsx b/ui/src/components/content-card.tsx index 457a016..1cf8220 100644 --- a/ui/src/components/content-card.tsx +++ b/ui/src/components/content-card.tsx @@ -1,14 +1,15 @@ import axios from "axios"; +import { useAtom } from "jotai"; import { DownloadCloud, FileText, Files, Trash2 } from "lucide-react"; import { toast } from "react-hot-toast"; import { getFiles } from "../actions/getFiles"; -import { useAtom } from "jotai"; -import { filesAtom, sizeAtom } from "../store"; import { getSize } from "../actions/getSize"; +import { filesAtom, sizeAtom } from "../store"; +import FileDataModal from "./file-data-modal"; import RenameModal from "./rename-modal"; +import ResizeModal from "./resize-modal"; import { Button } from "./ui/button"; import { Dialog, DialogTrigger } from "./ui/dialog"; -import FileDataModal from "./file-data-modal"; type TContentCardProps = { file_name?: string; @@ -100,6 +101,9 @@ const ContentCard: React.FC = ({ + {type === 'images' && ( + + )} {/* Destructive buttons */}
diff --git a/ui/src/components/resize-modal.tsx b/ui/src/components/resize-modal.tsx new file mode 100644 index 0000000..a118a9c --- /dev/null +++ b/ui/src/components/resize-modal.tsx @@ -0,0 +1,118 @@ +import handleResizeImage from "@/actions/handleResizeImage"; +import { FileMetadata } from "@/types/fileMetadata"; +import { ImageDimensions } from "@/types/imageDimensions"; +import axios from "axios"; +import { Scaling } from "lucide-react"; +import { useEffect, useState } from "react"; +import toast from "react-hot-toast"; +import { Button } from "./ui/button"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "./ui/dialog"; +import { Input } from "./ui/input"; +import { Label } from "./ui/label"; + +type ResizeModalProps = { + filename: string; +}; + + +const ResizeModal: React.FC = ({ filename }) => { + const [resizeFormData, setResizeFormData] = useState({ + width: 0, + height: 0, + }); + + const handleInputChange = (e: React.ChangeEvent) => { + const { name, value } = e.target; + + const formattedValue = value.replace(/\D/g, ''); + const positiveIntegerValue = formattedValue === '' ? 0 : parseInt(formattedValue, 10); + + setResizeFormData({ + ...resizeFormData, + [name]: positiveIntegerValue, + }); + } + + useEffect(() => { + if (filename) { + axios + .get( + `/api/cdn/image/${filename}` + ) + .then((res) => { + toast.dismiss(); + if (res.status === 200) { + setResizeFormData({ + width: res.data.width ?? 0, + height: res.data.height ?? 0, + }) + } + }) + .catch((err) => { + toast.dismiss(); + toast.error(err.message); + }); + } + axios; + }, [filename]); + + return ( + + + + + +
handleResizeImage(e, resizeFormData, filename)} + > + + Resize image + + Change the height and width of the image. Click save when you're done. + + +
+
+ + +
+ +
+ + +
+
+ + + +
+
+
+ ); +}; + +export default ResizeModal; diff --git a/ui/src/types/imageDimensions.ts b/ui/src/types/imageDimensions.ts new file mode 100644 index 0000000..cd7ae70 --- /dev/null +++ b/ui/src/types/imageDimensions.ts @@ -0,0 +1,4 @@ +export type ImageDimensions = { + width: number; + height: number; +} \ No newline at end of file