refactor #27

Merged
rov merged 3 commits from refactor into main 2026-03-28 19:47:51 -03:00
2 changed files with 57 additions and 17 deletions
Showing only changes of commit 32c3d4ad3b - Show all commits

View File

@ -6,8 +6,11 @@ import { cn } from "@/lib/utils";
function Progress({
className,
value,
indicatorClassName,
...props
}: React.ComponentProps<typeof ProgressPrimitive.Root>) {
}: React.ComponentProps<typeof ProgressPrimitive.Root> & {
indicatorClassName?: string;
}) {
return (
<ProgressPrimitive.Root
data-slot="progress"
@ -19,7 +22,10 @@ function Progress({
>
<ProgressPrimitive.Indicator
data-slot="progress-indicator"
className="h-full w-full flex-1 bg-primary transition-all"
className={cn(
"h-full w-full flex-1 bg-primary transition-all",
indicatorClassName,
)}
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
/>
</ProgressPrimitive.Root>

View File

@ -1,5 +1,5 @@
import axios from "axios";
import { FileUp } from "lucide-react";
import { FileUp, XCircle } from "lucide-react";
import type React from "react";
import { useState } from "react";
import { toast } from "sonner";
@ -33,6 +33,7 @@ export const MangaManualImportDialog = ({
const [uploadProgress, setUploadProgress] = useState<Record<string, number>>(
{},
);
const [uploadErrors, setUploadErrors] = useState<Record<string, boolean>>({});
const { mutateAsync: requestPresignedUrl } = useRequestPresignedImport();
@ -49,6 +50,7 @@ export const MangaManualImportDialog = ({
setIsUploading(true);
setUploadProgress({});
setUploadErrors({});
let hasError = false;
for (const file of files) {
@ -85,6 +87,7 @@ export const MangaManualImportDialog = ({
} catch (error) {
console.error(`Error uploading ${file.name}:`, error);
hasError = true;
setUploadErrors((prev) => ({ ...prev, [file.name]: true }));
toast.error(`Failed to import ${file.name}`);
}
}
@ -96,6 +99,7 @@ export const MangaManualImportDialog = ({
setMalId("");
setAniListId("");
setUploadProgress({});
setUploadErrors({});
onFileImportDialogOpenChange(false);
toast.success("Manga imported successfully! Backend will process it.");
}
@ -223,10 +227,23 @@ export const MangaManualImportDialog = ({
0,
) / files.length
}
indicatorClassName={
Math.round(
files.reduce(
(acc, file) => acc + (uploadProgress[file.name] || 0),
0,
) / files.length,
) === 100
? "bg-green-500"
: ""
}
/>
</div>
<div className="space-y-3">
{files.map((file) => (
<div className="space-y-3 max-h-60 overflow-y-auto pr-2">
{files.map((file) => {
const isError = uploadErrors[file.name];
const progress = uploadProgress[file.name] || 0;
return (
<div key={file.name} className="space-y-1">
<div className="flex justify-between text-xs text-muted-foreground">
<span
@ -235,11 +252,27 @@ export const MangaManualImportDialog = ({
>
{file.name}
</span>
<span>{uploadProgress[file.name] || 0}%</span>
{isError ? (
<span className="flex items-center gap-1 font-medium text-destructive">
<XCircle className="h-3 w-3" /> Failed
</span>
) : (
<span>{progress}%</span>
)}
</div>
<Progress value={uploadProgress[file.name] || 0} />
<Progress
value={isError ? 100 : progress}
indicatorClassName={
isError
? "bg-destructive"
: progress === 100
? "bg-green-500"
: ""
}
/>
</div>
))}
);
})}
</div>
</div>
)}
@ -251,6 +284,7 @@ export const MangaManualImportDialog = ({
onClick={() => {
setFiles(null);
setUploadProgress({});
setUploadErrors({});
onFileImportDialogOpenChange(false);
}}
>