mirror of
https://github.com/kyantech/Palmr.git
synced 2025-10-22 22:02:00 +00:00
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:
Binary file not shown.
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 141 KiB |
@@ -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">
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user