blob: e016402d71f108db67f23137993a01503e742d68 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
"use client";
import { FileText, CheckCircle2, XCircle, Loader2 } from "lucide-react";
import { Progress } from "@/components/ui/progress";
import { FileUploadProgress } from "../hooks/use-file-upload-with-progress";
interface FileUploadProgressListProps {
fileProgresses: FileUploadProgress[];
}
export function FileUploadProgressList({ fileProgresses }: FileUploadProgressListProps) {
if (fileProgresses.length === 0) {
return null;
}
return (
<div className="space-y-3">
<h4 className="text-sm font-medium">
파일 업로드 진행 상황 ({fileProgresses.length}개)
</h4>
<div className="max-h-64 overflow-auto space-y-2">
{fileProgresses.map((fileProgress, index) => (
<FileUploadProgressItem key={index} fileProgress={fileProgress} />
))}
</div>
</div>
);
}
interface FileUploadProgressItemProps {
fileProgress: FileUploadProgress;
}
function FileUploadProgressItem({ fileProgress }: FileUploadProgressItemProps) {
const { file, progress, status, error } = fileProgress;
const getStatusIcon = () => {
switch (status) {
case "completed":
return <CheckCircle2 className="h-4 w-4 text-green-600 shrink-0" />;
case "error":
return <XCircle className="h-4 w-4 text-red-600 shrink-0" />;
case "uploading":
return <Loader2 className="h-4 w-4 text-primary shrink-0 animate-spin" />;
default:
return <FileText className="h-4 w-4 text-muted-foreground shrink-0" />;
}
};
const getStatusColor = () => {
switch (status) {
case "completed":
return "border-green-200 bg-green-50/50";
case "error":
return "border-red-200 bg-red-50/50";
case "uploading":
return "border-primary/30 bg-primary/5";
default:
return "border-muted bg-muted/30";
}
};
return (
<div className={`border rounded-lg p-3 space-y-2 ${getStatusColor()}`}>
<div className="flex items-center gap-2">
{getStatusIcon()}
<div className="flex-1 min-w-0">
<p className="text-sm font-medium truncate">{file.name}</p>
<p className="text-xs text-muted-foreground">
{(file.size / 1024 / 1024).toFixed(2)} MB
</p>
</div>
{status !== "pending" && (
<div className="text-sm font-medium">
{status === "completed" ? (
<span className="text-green-600">완료</span>
) : status === "error" ? (
<span className="text-red-600">실패</span>
) : (
<span className="text-primary">{Math.round(progress)}%</span>
)}
</div>
)}
</div>
{/* Progress Bar */}
{status === "uploading" && (
<Progress value={progress} className="h-1.5" />
)}
{/* 에러 메시지 */}
{status === "error" && error && (
<p className="text-xs text-red-600">{error}</p>
)}
</div>
);
}
|