From 04ec2a27f9d6146b4361ae9780dc25bf39960f0f Mon Sep 17 00:00:00 2001 From: Barbara Peric Date: Wed, 5 Nov 2025 11:59:35 +0000 Subject: [PATCH 1/2] feat: add UploadButton component for file uploads This commit introduces a new UploadButton component that allows users to upload files with error handling for file size limits. The component utilizes Radix UI for form control and includes a button with a loading state during uploads. It also provides user feedback for file size errors. --- src/components/upload/upload-button.tsx | 69 +++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 src/components/upload/upload-button.tsx diff --git a/src/components/upload/upload-button.tsx b/src/components/upload/upload-button.tsx new file mode 100644 index 0000000..8f2f2c6 --- /dev/null +++ b/src/components/upload/upload-button.tsx @@ -0,0 +1,69 @@ +import { Root, FormControl, FormField, FormMessage } from '@radix-ui/react-form' +import { useRef, useState } from 'react' +import { PlusIcon } from 'lucide-react' + +import { ButtonBase as Button } from '../ui/button/button-base.tsx' +import { formatFileSize } from '@/utils/format-file-size.ts' + +interface UploadButtonProps { + onUpload: (file: File) => void + isUploading?: boolean + accept?: string[] + maxSize?: number +} + +export function UploadButton({ + onUpload, + isUploading = false, + accept = ['*'], + maxSize = 200_000_000, +}: UploadButtonProps) { + const fileInputRef = useRef(null) + const [error, setError] = useState(null) + + const handleButtonClick = () => { + fileInputRef.current?.click() + } + + const handleFileChange = (e: React.ChangeEvent) => { + const file = e.target.files?.[0] + if (file) { + onUpload(file) + if (file.size > maxSize) { + setError(`File is too large. Maximum size is ${formatFileSize(maxSize)}.`) + if (fileInputRef.current) fileInputRef.current.value = '' + return + } + + setError(null) + onUpload(file) + if (fileInputRef.current) fileInputRef.current.value = '' + } + } + + return ( + e.preventDefault()}> + + + + + + + + {error} + + + ) +} From b39282780de1dbbc486b5fa5da2cf81407d1add8 Mon Sep 17 00:00:00 2001 From: Barbara Peric Date: Wed, 5 Nov 2025 14:30:52 +0000 Subject: [PATCH 2/2] refactor: replace hardcoded max file size with constant in DragNDrop and UploadButton components This commit updates the DragNDrop and UploadButton components to use a centralized MAX_FILE_SIZE constant instead of hardcoded values for maximum file size. Additionally, it improves the structure of the UploadButton component by adjusting the layout and error message handling for better user experience. --- src/components/upload/drag-n-drop.tsx | 3 +- src/components/upload/upload-button.tsx | 47 +++++++++++++++---------- src/constants/files.ts | 1 + 3 files changed, 32 insertions(+), 19 deletions(-) create mode 100644 src/constants/files.ts diff --git a/src/components/upload/drag-n-drop.tsx b/src/components/upload/drag-n-drop.tsx index cc9b617..deed756 100644 --- a/src/components/upload/drag-n-drop.tsx +++ b/src/components/upload/drag-n-drop.tsx @@ -1,5 +1,6 @@ import { Root } from '@radix-ui/react-form' import { useState } from 'react' +import { MAX_FILE_SIZE } from '@/constants/files.ts' import { FilePicker } from '../file-picker/index.tsx' import { ButtonBase as Button } from '../ui/button/button-base.tsx' @@ -32,7 +33,7 @@ export default function DragNDrop({ onFileSelected, onUpload, isUploading }: Dra e.preventDefault()}> { setFile(file) if (file && onFileSelected) { diff --git a/src/components/upload/upload-button.tsx b/src/components/upload/upload-button.tsx index 8f2f2c6..99341cd 100644 --- a/src/components/upload/upload-button.tsx +++ b/src/components/upload/upload-button.tsx @@ -1,9 +1,9 @@ -import { Root, FormControl, FormField, FormMessage } from '@radix-ui/react-form' -import { useRef, useState } from 'react' +import { FormControl, FormField, FormMessage, Root } from '@radix-ui/react-form' import { PlusIcon } from 'lucide-react' - -import { ButtonBase as Button } from '../ui/button/button-base.tsx' +import { useRef, useState } from 'react' +import { MAX_FILE_SIZE } from '@/constants/files.ts' import { formatFileSize } from '@/utils/format-file-size.ts' +import { ButtonBase as Button } from '../ui/button/button-base.tsx' interface UploadButtonProps { onUpload: (file: File) => void @@ -16,19 +16,18 @@ export function UploadButton({ onUpload, isUploading = false, accept = ['*'], - maxSize = 200_000_000, + maxSize = MAX_FILE_SIZE, }: UploadButtonProps) { const fileInputRef = useRef(null) const [error, setError] = useState(null) - const handleButtonClick = () => { + function handleButtonClick() { fileInputRef.current?.click() } - const handleFileChange = (e: React.ChangeEvent) => { + function handleFileChange(e: React.ChangeEvent) { const file = e.target.files?.[0] if (file) { - onUpload(file) if (file.size > maxSize) { setError(`File is too large. Maximum size is ${formatFileSize(maxSize)}.`) if (fileInputRef.current) fileInputRef.current.value = '' @@ -42,7 +41,7 @@ export function UploadButton({ } return ( - e.preventDefault()}> + e.preventDefault()}> - - - {error} - +
+ +
+
+ {error && ( + + {error} + + )} +
) } diff --git a/src/constants/files.ts b/src/constants/files.ts new file mode 100644 index 0000000..ee8752a --- /dev/null +++ b/src/constants/files.ts @@ -0,0 +1 @@ +export const MAX_FILE_SIZE = 200_000_000