ERP-node/frontend/components/dashboard/widgets/DocumentWidget.tsx

243 lines
8.4 KiB
TypeScript

"use client";
import React, { useState } from "react";
import { FileText, Download, Calendar, Folder, Search } from "lucide-react";
interface Document {
id: string;
name: string;
category: "계약서" | "보험" | "세금계산서" | "기타";
size: string;
uploadDate: string;
url: string;
description?: string;
}
// 목 데이터
const mockDocuments: Document[] = [
{
id: "1",
name: "2025년 1월 세금계산서.pdf",
category: "세금계산서",
size: "1.2 MB",
uploadDate: "2025-01-05",
url: "/documents/tax-invoice-202501.pdf",
description: "1월 매출 세금계산서",
},
{
id: "2",
name: "차량보험증권_서울12가3456.pdf",
category: "보험",
size: "856 KB",
uploadDate: "2024-12-20",
url: "/documents/insurance-vehicle-1.pdf",
description: "1톤 트럭 종합보험",
},
{
id: "3",
name: "운송계약서_ABC물류.pdf",
category: "계약서",
size: "2.4 MB",
uploadDate: "2024-12-15",
url: "/documents/contract-abc-logistics.pdf",
description: "ABC물류 연간 운송 계약",
},
{
id: "4",
name: "2024년 12월 세금계산서.pdf",
category: "세금계산서",
size: "1.1 MB",
uploadDate: "2024-12-05",
url: "/documents/tax-invoice-202412.pdf",
},
{
id: "5",
name: "화물배상책임보험증권.pdf",
category: "보험",
size: "720 KB",
uploadDate: "2024-11-30",
url: "/documents/cargo-insurance.pdf",
description: "화물 배상책임보험",
},
{
id: "6",
name: "차고지 임대계약서.pdf",
category: "계약서",
size: "1.8 MB",
uploadDate: "2024-11-15",
url: "/documents/garage-lease-contract.pdf",
},
];
export default function DocumentWidget() {
const [documents] = useState<Document[]>(mockDocuments);
const [filter, setFilter] = useState<"all" | Document["category"]>("all");
const [searchTerm, setSearchTerm] = useState("");
const filteredDocuments = documents.filter((doc) => {
const matchesFilter = filter === "all" || doc.category === filter;
const matchesSearch =
searchTerm === "" ||
doc.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
doc.description?.toLowerCase().includes(searchTerm.toLowerCase());
return matchesFilter && matchesSearch;
});
const getCategoryIcon = (category: Document["category"]) => {
switch (category) {
case "계약서":
return "📄";
case "보험":
return "🛡️";
case "세금계산서":
return "💰";
case "기타":
return "📁";
}
};
const getCategoryColor = (category: Document["category"]) => {
switch (category) {
case "계약서":
return "bg-blue-100 text-blue-700";
case "보험":
return "bg-green-100 text-green-700";
case "세금계산서":
return "bg-amber-100 text-amber-700";
case "기타":
return "bg-gray-100 text-gray-700";
}
};
const handleDownload = (doc: Document) => {
// 실제로는 백엔드 API 호출
alert(`다운로드: ${doc.name}\n(실제 구현 시 파일 다운로드 처리)`);
};
const stats = {
total: documents.length,
contract: documents.filter((d) => d.category === "계약서").length,
insurance: documents.filter((d) => d.category === "보험").length,
tax: documents.filter((d) => d.category === "세금계산서").length,
};
return (
<div className="flex h-full flex-col bg-gradient-to-br from-slate-50 to-blue-50">
{/* 헤더 */}
<div className="border-b border-gray-200 bg-white px-4 py-3">
<div className="mb-3 flex items-center justify-between">
<h3 className="text-lg font-bold text-gray-800">📂 </h3>
<button className="rounded-lg bg-primary px-3 py-1.5 text-sm text-white transition-colors hover:bg-primary/90">
+
</button>
</div>
{/* 통계 */}
<div className="mb-3 grid grid-cols-4 gap-2 text-xs">
<div className="rounded bg-gray-50 px-2 py-1.5 text-center">
<div className="font-bold text-gray-700">{stats.total}</div>
<div className="text-gray-600"></div>
</div>
<div className="rounded bg-blue-50 px-2 py-1.5 text-center">
<div className="font-bold text-blue-700">{stats.contract}</div>
<div className="text-blue-600"></div>
</div>
<div className="rounded bg-green-50 px-2 py-1.5 text-center">
<div className="font-bold text-green-700">{stats.insurance}</div>
<div className="text-green-600"></div>
</div>
<div className="rounded bg-amber-50 px-2 py-1.5 text-center">
<div className="font-bold text-amber-700">{stats.tax}</div>
<div className="text-amber-600"></div>
</div>
</div>
{/* 검색 */}
<div className="mb-3 relative">
<Search className="absolute left-3 top-2.5 h-4 w-4 text-gray-400" />
<input
type="text"
placeholder="문서명 검색..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full rounded border border-gray-300 py-2 pl-10 pr-3 text-sm focus:border-primary focus:outline-none"
/>
</div>
{/* 필터 */}
<div className="flex gap-2">
{(["all", "계약서", "보험", "세금계산서", "기타"] as const).map((f) => (
<button
key={f}
onClick={() => setFilter(f)}
className={`rounded px-3 py-1 text-xs font-medium transition-colors ${
filter === f ? "bg-primary text-white" : "bg-gray-100 text-gray-600 hover:bg-gray-200"
}`}
>
{f === "all" ? "전체" : f}
</button>
))}
</div>
</div>
{/* 문서 리스트 */}
<div className="flex-1 overflow-y-auto p-4">
{filteredDocuments.length === 0 ? (
<div className="flex h-full items-center justify-center text-gray-400">
<div className="text-center">
<div className="mb-2 text-4xl">📭</div>
<div> </div>
</div>
</div>
) : (
<div className="space-y-2">
{filteredDocuments.map((doc) => (
<div
key={doc.id}
className="group flex items-center gap-3 rounded-lg border border-gray-200 bg-white p-3 shadow-sm transition-all hover:border-primary hover:shadow-md"
>
{/* 아이콘 */}
<div className="flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-lg bg-gray-50 text-2xl">
{getCategoryIcon(doc.category)}
</div>
{/* 정보 */}
<div className="flex-1 min-w-0">
<div className="flex items-start justify-between gap-2">
<div className="flex-1 min-w-0">
<div className="truncate font-medium text-gray-800">{doc.name}</div>
{doc.description && (
<div className="mt-0.5 truncate text-xs text-gray-600">{doc.description}</div>
)}
<div className="mt-1 flex items-center gap-3 text-xs text-gray-500">
<span className={`rounded px-2 py-0.5 ${getCategoryColor(doc.category)}`}>
{doc.category}
</span>
<span className="flex items-center gap-1">
<Calendar className="h-3 w-3" />
{new Date(doc.uploadDate).toLocaleDateString()}
</span>
<span>{doc.size}</span>
</div>
</div>
</div>
</div>
{/* 다운로드 버튼 */}
<button
onClick={() => handleDownload(doc)}
className="flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-lg bg-primary text-white transition-colors hover:bg-primary/90"
title="다운로드"
>
<Download className="h-4 w-4" />
</button>
</div>
))}
</div>
)}
</div>
</div>
);
}