mirror of
https://github.com/spliit-app/spliit.git
synced 2026-03-09 13:49:04 +01:00
Limit file upload size on the client (#84)
This commit is contained in:
@@ -26,7 +26,7 @@ import {
|
|||||||
import { ToastAction } from '@/components/ui/toast'
|
import { ToastAction } from '@/components/ui/toast'
|
||||||
import { useToast } from '@/components/ui/use-toast'
|
import { useToast } from '@/components/ui/use-toast'
|
||||||
import { useMediaQuery } from '@/lib/hooks'
|
import { useMediaQuery } from '@/lib/hooks'
|
||||||
import { formatCurrency, formatExpenseDate } from '@/lib/utils'
|
import { formatCurrency, formatExpenseDate, formatFileSize } from '@/lib/utils'
|
||||||
import { Category } from '@prisma/client'
|
import { Category } from '@prisma/client'
|
||||||
import { ChevronRight, FileQuestion, Loader2, Receipt } from 'lucide-react'
|
import { ChevronRight, FileQuestion, Loader2, Receipt } from 'lucide-react'
|
||||||
import { getImageData, usePresignedUpload } from 'next-s3-upload'
|
import { getImageData, usePresignedUpload } from 'next-s3-upload'
|
||||||
@@ -40,6 +40,8 @@ type Props = {
|
|||||||
categories: Category[]
|
categories: Category[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MAX_FILE_SIZE = 5 * 1024 ** 2
|
||||||
|
|
||||||
export function CreateFromReceiptButton({
|
export function CreateFromReceiptButton({
|
||||||
groupId,
|
groupId,
|
||||||
groupCurrency,
|
groupCurrency,
|
||||||
@@ -56,6 +58,17 @@ export function CreateFromReceiptButton({
|
|||||||
const isDesktop = useMediaQuery('(min-width: 640px)')
|
const isDesktop = useMediaQuery('(min-width: 640px)')
|
||||||
|
|
||||||
const handleFileChange = async (file: File) => {
|
const handleFileChange = async (file: File) => {
|
||||||
|
if (file.size > MAX_FILE_SIZE) {
|
||||||
|
toast({
|
||||||
|
title: 'The file is too big',
|
||||||
|
description: `The maximum file size you can upload is ${formatFileSize(
|
||||||
|
MAX_FILE_SIZE,
|
||||||
|
)}. Yours is ${formatFileSize(file.size)}.`,
|
||||||
|
variant: 'destructive',
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const upload = async () => {
|
const upload = async () => {
|
||||||
try {
|
try {
|
||||||
setPending(true)
|
setPending(true)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { ToastAction } from '@/components/ui/toast'
|
|||||||
import { useToast } from '@/components/ui/use-toast'
|
import { useToast } from '@/components/ui/use-toast'
|
||||||
import { randomId } from '@/lib/api'
|
import { randomId } from '@/lib/api'
|
||||||
import { ExpenseFormValues } from '@/lib/schemas'
|
import { ExpenseFormValues } from '@/lib/schemas'
|
||||||
|
import { formatFileSize } from '@/lib/utils'
|
||||||
import { Loader2, Plus, Trash, X } from 'lucide-react'
|
import { Loader2, Plus, Trash, X } from 'lucide-react'
|
||||||
import { getImageData, usePresignedUpload } from 'next-s3-upload'
|
import { getImageData, usePresignedUpload } from 'next-s3-upload'
|
||||||
import Image from 'next/image'
|
import Image from 'next/image'
|
||||||
@@ -27,12 +28,25 @@ type Props = {
|
|||||||
updateDocuments: (documents: ExpenseFormValues['documents']) => void
|
updateDocuments: (documents: ExpenseFormValues['documents']) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const MAX_FILE_SIZE = 5 * 1024 ** 2
|
||||||
|
|
||||||
export function ExpenseDocumentsInput({ documents, updateDocuments }: Props) {
|
export function ExpenseDocumentsInput({ documents, updateDocuments }: Props) {
|
||||||
const [pending, setPending] = useState(false)
|
const [pending, setPending] = useState(false)
|
||||||
const { FileInput, openFileDialog, uploadToS3 } = usePresignedUpload() // use presigned uploads to addtionally support providers other than AWS
|
const { FileInput, openFileDialog, uploadToS3 } = usePresignedUpload() // use presigned uploads to addtionally support providers other than AWS
|
||||||
const { toast } = useToast()
|
const { toast } = useToast()
|
||||||
|
|
||||||
const handleFileChange = async (file: File) => {
|
const handleFileChange = async (file: File) => {
|
||||||
|
if (file.size > MAX_FILE_SIZE) {
|
||||||
|
toast({
|
||||||
|
title: 'The file is too big',
|
||||||
|
description: `The maximum file size you can upload is ${formatFileSize(
|
||||||
|
MAX_FILE_SIZE,
|
||||||
|
)}. Yours is ${formatFileSize(file.size)}.`,
|
||||||
|
variant: 'destructive',
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const upload = async () => {
|
const upload = async () => {
|
||||||
try {
|
try {
|
||||||
setPending(true)
|
setPending(true)
|
||||||
|
|||||||
@@ -29,3 +29,16 @@ export function formatCurrency(currency: string, amount: number) {
|
|||||||
const formattedAmount = format.format(amount / 100)
|
const formattedAmount = format.format(amount / 100)
|
||||||
return `${currency} ${formattedAmount}`
|
return `${currency} ${formattedAmount}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function formatFileSize(size: number) {
|
||||||
|
const formatNumber = (num: number) =>
|
||||||
|
num.toLocaleString('en-US', {
|
||||||
|
minimumFractionDigits: 0,
|
||||||
|
maximumFractionDigits: 1,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (size > 1024 ** 3) return `${formatNumber(size / 1024 ** 3)} GB`
|
||||||
|
if (size > 1024 ** 2) return `${formatNumber(size / 1024 ** 2)} MB`
|
||||||
|
if (size > 1024) return `${formatNumber(size / 1024)} kB`
|
||||||
|
return `${formatNumber(size)} B`
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user