feat: enhance file upload modal with success toast and file size formatting

- Added a success toast notification to the file upload modal, improving user feedback upon completion of uploads.
- Implemented a utility function to format file sizes for better readability in the upload status display.
- Reset the success toast flag in various scenarios to ensure accurate notifications during multiple upload sessions.
- Updated the favicon.ico file to reflect recent design changes.
This commit is contained in:
Daniel Luiz Alves
2025-07-01 11:10:48 -03:00
parent 8a954e14fa
commit 8db3304b56
3 changed files with 16 additions and 8 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 165 KiB

After

Width:  |  Height:  |  Size: 141 KiB

View File

@@ -12,6 +12,7 @@ import { Progress } from "@/components/ui/progress";
import { checkFile, getPresignedUrl, registerFile } from "@/http/endpoints";
import { getFileIcon } from "@/utils/file-icons";
import { generateSafeFileName } from "@/utils/file-utils";
import { formatFileSize } from "@/utils/format-file-size";
import getErrorData from "@/utils/getErrorData";
interface UploadFileModalProps {
@@ -84,6 +85,7 @@ export function UploadFileModal({ isOpen, onClose, onSuccess }: UploadFileModalP
const [fileUploads, setFileUploads] = useState<FileUpload[]>([]);
const [isDragOver, setIsDragOver] = useState(false);
const [showConfirmation, setShowConfirmation] = useState(false);
const [hasShownSuccessToast, setHasShownSuccessToast] = useState(false);
const fileInputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
@@ -122,6 +124,7 @@ export function UploadFileModal({ isOpen, onClose, onSuccess }: UploadFileModalP
const newUploads = Array.from(files).map(createFileUpload);
setFileUploads((prev) => [...prev, ...newUploads]);
setHasShownSuccessToast(false);
};
const handleFileInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
@@ -295,6 +298,9 @@ export function UploadFileModal({ isOpen, onClose, onSuccess }: UploadFileModalP
const startUploads = async () => {
const pendingUploads = fileUploads.filter((u) => u.status === UploadStatus.PENDING);
// Reset the toast flag when starting new uploads
setHasShownSuccessToast(false);
const uploadPromises = pendingUploads.map((upload) => uploadFile(upload));
await Promise.all(uploadPromises);
@@ -305,7 +311,7 @@ export function UploadFileModal({ isOpen, onClose, onSuccess }: UploadFileModalP
u.status === UploadStatus.SUCCESS || u.status === UploadStatus.ERROR || u.status === UploadStatus.CANCELLED
);
if (allComplete) {
if (allComplete && !hasShownSuccessToast) {
const successCount = currentUploads.filter((u) => u.status === UploadStatus.SUCCESS).length;
const errorCount = currentUploads.filter((u) => u.status === UploadStatus.ERROR).length;
@@ -315,6 +321,7 @@ export function UploadFileModal({ isOpen, onClose, onSuccess }: UploadFileModalP
? t("uploadFile.partialSuccess", { success: successCount, error: errorCount })
: t("uploadFile.allSuccess", { count: successCount })
);
setHasShownSuccessToast(true);
onSuccess?.();
}
}
@@ -339,6 +346,7 @@ export function UploadFileModal({ isOpen, onClose, onSuccess }: UploadFileModalP
setFileUploads([]);
setShowConfirmation(false);
setHasShownSuccessToast(false); // Reset toast flag when closing
onClose();
};
@@ -417,7 +425,7 @@ export function UploadFileModal({ isOpen, onClose, onSuccess }: UploadFileModalP
<p className="text-sm font-medium truncate text-foreground">{upload.file.name}</p>
{getStatusIcon(upload.status)}
</div>
<p className="text-xs text-muted-foreground">{(upload.file.size / 1024).toFixed(1)} KB</p>
<p className="text-xs text-muted-foreground">{formatFileSize(upload.file.size)}</p>
{upload.status === UploadStatus.UPLOADING && (
<div className="mt-1">

View File

@@ -13,8 +13,8 @@ interface Config {
}
/**
* Hook para buscar configurações de forma segura
* Substitui o uso direto de getAllConfigs que expunha dados sensíveis
* Hook to fetch configurations securely
* Replaces direct use of getAllConfigs which exposed sensitive data
*/
export function useSecureConfigs() {
const [configs, setConfigs] = useState<Config[]>([]);
@@ -48,8 +48,8 @@ export function useSecureConfigs() {
}
/**
* Hook para buscar configurações para administradores
* REQUER PERMISSÕES DE ADMIN - retorna erro se usuário não for admin
* Hook to fetch configurations for administrators
* REQUIRES ADMIN PERMISSIONS - returns error if user is not admin
*/
export function useAdminConfigs() {
const [configs, setConfigs] = useState<Config[]>([]);
@@ -95,8 +95,8 @@ export function useAdminConfigs() {
}
/**
* Hook para buscar um valor específico de configuração
* Útil quando você só precisa de um valor específico (ex: smtpEnabled)
* Hook to fetch a specific configuration value
* Useful when you only need a specific value (e.g. smtpEnabled)
*/
export function useSecureConfigValue(key: string) {
const [value, setValue] = useState<string | null>(null);