@@ -3,6 +3,7 @@ import JSZip from "jszip";
33import { Download , ImageIcon , Inbox , RefreshCcw } from "lucide-react" ;
44import { useEffect , useRef , useState } from "react" ;
55import { PhotoProvider } from "react-photo-view" ;
6+ import { toast } from "sonner" ;
67
78import ImagePreviewCard from "./image-preview-card" ;
89import ImageQualitySlider from "./image-quality-slider" ;
@@ -31,6 +32,45 @@ const ImageCompressor = () => {
3132 const [ compressProgress , setCompressProgress ] = useState < number > ( 0 ) ;
3233 const dropAreaRef = useRef < HTMLLabelElement > ( null ) ;
3334 const compressedImagesRef = useRef < HTMLDivElement > ( null ) ;
35+
36+ // Allowed image formats
37+ const allowedFormats = [ "image/jpeg" , "image/jpg" , "image/png" , "image/webp" ] ;
38+
39+ // Validate file type
40+ const validateFileType = ( file : File ) : boolean => {
41+ return allowedFormats . includes ( file . type . toLowerCase ( ) ) ;
42+ } ;
43+
44+ // Filter valid files and show error for invalid ones
45+ const filterValidFiles = ( files : FileList | File [ ] ) : File [ ] => {
46+ const filesArray = Array . from ( files ) ;
47+ const validFiles : File [ ] = [ ] ;
48+ const invalidFiles : File [ ] = [ ] ;
49+
50+ filesArray . forEach ( ( file ) => {
51+ if ( validateFileType ( file ) ) {
52+ validFiles . push ( file ) ;
53+ } else {
54+ invalidFiles . push ( file ) ;
55+ }
56+ } ) ;
57+
58+ // Show error toast for invalid files
59+ if ( invalidFiles . length > 0 ) {
60+ const invalidFileNames = invalidFiles . map ( ( file ) => file . name ) . join ( ", " ) ;
61+ toast . error (
62+ `Invalid file! Please upload only JPG, JPEG, PNG, or WEBP files.` ,
63+ {
64+ description : invalidFileNames ,
65+ duration : 5000 ,
66+ position : "top-right" ,
67+ }
68+ ) ;
69+ }
70+
71+ return validFiles ;
72+ } ;
73+
3474 const onImageQualityChange = async (
3575 event : React . ChangeEvent < HTMLInputElement >
3676 ) => {
@@ -40,9 +80,13 @@ const ImageCompressor = () => {
4080 const handleImageUpload = async ( e : React . ChangeEvent < HTMLInputElement > ) => {
4181 e . preventDefault ( ) ;
4282 if ( e . target . files ) {
83+ const validFiles = filterValidFiles ( e . target . files ) ;
84+ if ( validFiles . length === 0 ) {
85+ return ; // No valid files to process
86+ }
4387 setCompressedImages ( [ ] ) ;
4488 setCompressProgress ( 0 ) ;
45- setFilelist ( e . target . files ) ;
89+ setFilelist ( validFiles ) ;
4690 }
4791 } ;
4892
@@ -144,9 +188,15 @@ const ImageCompressor = () => {
144188 e . preventDefault ( ) ;
145189 e . stopPropagation ( ) ;
146190 setIsDragActive ( false ) ;
191+
192+ const validFiles = filterValidFiles ( e . dataTransfer . files ) ;
193+ if ( validFiles . length === 0 ) {
194+ return ; // No valid files to process
195+ }
196+
147197 setCompressedImages ( [ ] ) ;
148198 setCompressProgress ( 0 ) ;
149- setFilelist ( e . dataTransfer . files ) ;
199+ setFilelist ( validFiles ) ;
150200 } ;
151201
152202 const handleDownload = ( ) => {
@@ -212,7 +262,7 @@ const ImageCompressor = () => {
212262 < input
213263 multiple
214264 type = "file"
215- accept = "image/* "
265+ accept = "image/jpeg,image/jpg,image/png,image/webp "
216266 onChange = { handleImageUpload }
217267 style = { { display : "none" } }
218268 id = "file-input"
0 commit comments