summaryrefslogtreecommitdiff
path: root/lib/dolce/components/file-upload-progress-list.tsx
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>
  );
}