ERP-node/frontend/components/admin/dashboard/widgets/DriverManagementWidget.tsx

160 lines
5.8 KiB
TypeScript

"use client";
import React, { useState, useEffect } from "react";
import { DashboardElement, DriverManagementConfig, DriverInfo } from "../types";
import { DriverListView } from "./DriverListView";
import { DriverManagementSettings } from "./DriverManagementSettings";
import { MOCK_DRIVERS } from "./driverMockData";
import { filterDrivers, sortDrivers, DEFAULT_VISIBLE_COLUMNS } from "./driverUtils";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Settings, Search, RefreshCw } from "lucide-react";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
interface DriverManagementWidgetProps {
element: DashboardElement;
onConfigUpdate?: (config: DriverManagementConfig) => void;
}
export function DriverManagementWidget({ element, onConfigUpdate }: DriverManagementWidgetProps) {
const [drivers, setDrivers] = useState<DriverInfo[]>(MOCK_DRIVERS);
const [searchTerm, setSearchTerm] = useState("");
const [settingsOpen, setSettingsOpen] = useState(false);
const [lastRefresh, setLastRefresh] = useState(new Date());
// 기본 설정
const config = element.driverManagementConfig || {
viewType: "list",
autoRefreshInterval: 30,
visibleColumns: DEFAULT_VISIBLE_COLUMNS,
theme: "light",
statusFilter: "all",
sortBy: "name",
sortOrder: "asc",
};
// 자동 새로고침
useEffect(() => {
if (config.autoRefreshInterval <= 0) return;
const interval = setInterval(() => {
// 실제 환경에서는 API 호출
setDrivers(MOCK_DRIVERS);
setLastRefresh(new Date());
}, config.autoRefreshInterval * 1000);
return () => clearInterval(interval);
}, [config.autoRefreshInterval]);
// 수동 새로고침
const handleRefresh = () => {
setDrivers(MOCK_DRIVERS);
setLastRefresh(new Date());
};
// 설정 저장
const handleSaveSettings = (newConfig: DriverManagementConfig) => {
onConfigUpdate?.(newConfig);
setSettingsOpen(false);
};
// 필터링 및 정렬
const filteredDrivers = sortDrivers(
filterDrivers(drivers, config.statusFilter, searchTerm),
config.sortBy,
config.sortOrder,
);
// 컴팩트 모드 판단 (위젯 크기가 작을 때)
const isCompact = element.size.width < 400 || element.size.height < 300;
return (
<div className="relative flex h-full w-full flex-col bg-white">
{/* 헤더 - 컴팩트 모드가 아닐 때만 표시 */}
{!isCompact && (
<div className="flex-shrink-0 border-b border-gray-200 bg-gray-50 px-3 py-2">
<div className="flex items-center justify-between gap-2">
{/* 검색 */}
<div className="relative max-w-xs flex-1">
<Search className="absolute left-2 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-gray-400" />
<Input
type="text"
placeholder="기사명, 차량번호 검색"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="h-8 pl-8 text-xs"
/>
</div>
{/* 상태 필터 */}
<Select
value={config.statusFilter}
onValueChange={(value) => {
onConfigUpdate?.({
...config,
statusFilter: value as DriverManagementConfig["statusFilter"],
});
}}
>
<SelectTrigger className="h-8 w-24 text-xs">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="all"></SelectItem>
<SelectItem value="driving"></SelectItem>
<SelectItem value="standby"></SelectItem>
<SelectItem value="resting"></SelectItem>
<SelectItem value="maintenance"></SelectItem>
</SelectContent>
</Select>
{/* 새로고침 버튼 */}
<Button variant="ghost" size="icon" className="h-8 w-8" onClick={handleRefresh}>
<RefreshCw className="h-4 w-4" />
</Button>
{/* 설정 버튼 */}
<Popover open={settingsOpen} onOpenChange={setSettingsOpen}>
<PopoverTrigger asChild>
<Button variant="ghost" size="icon" className="h-8 w-8">
<Settings className="h-4 w-4" />
</Button>
</PopoverTrigger>
<PopoverContent className="w-[500px] p-0" align="end">
<DriverManagementSettings
config={config}
onSave={handleSaveSettings}
onClose={() => setSettingsOpen(false)}
/>
</PopoverContent>
</Popover>
</div>
{/* 통계 정보 */}
<div className="mt-2 flex items-center gap-3 text-xs text-gray-600">
<span>
<span className="font-semibold text-gray-900">{filteredDrivers.length}</span>
</span>
<span className="text-gray-400">|</span>
<span>
{" "}
<span className="font-semibold text-green-600">
{filteredDrivers.filter((d) => d.status === "driving").length}
</span>
</span>
<span className="text-gray-400">|</span>
<span className="text-xs text-gray-500"> : {lastRefresh.toLocaleTimeString("ko-KR")}</span>
</div>
</div>
)}
{/* 리스트 뷰 */}
<div className="flex-1 overflow-hidden">
<DriverListView drivers={filteredDrivers} config={config} isCompact={isCompact} />
</div>
</div>
);
}